brintos

brintos / llvm-project-archived public Read only

0
0
Text · 91.0 KiB · 51f65bf Raw
2592 lines · cpp
1//===- llvm/unittest/Support/Path.cpp - Path tests ------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/Support/Path.h"10#include "llvm/ADT/STLExtras.h"11#include "llvm/ADT/ScopeExit.h"12#include "llvm/ADT/SmallVector.h"13#include "llvm/BinaryFormat/Magic.h"14#include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX15#include "llvm/Support/Compiler.h"16#include "llvm/Support/ConvertUTF.h"17#include "llvm/Support/Duration.h"18#include "llvm/Support/Errc.h"19#include "llvm/Support/ErrorHandling.h"20#include "llvm/Support/FileSystem.h"21#include "llvm/Support/FileUtilities.h"22#include "llvm/Support/MemoryBuffer.h"23#include "llvm/Support/raw_ostream.h"24#include "llvm/TargetParser/Host.h"25#include "llvm/TargetParser/Triple.h"26#include "llvm/Testing/Support/Error.h"27#include "llvm/Testing/Support/SupportHelpers.h"28#include "gmock/gmock.h"29#include "gtest/gtest.h"30 31#ifdef _WIN3232#include "llvm/ADT/ArrayRef.h"33#include "llvm/Support/Chrono.h"34#include "llvm/Support/Windows/WindowsSupport.h"35#include <windows.h>36#include <winerror.h>37#endif38 39#ifdef LLVM_ON_UNIX40#include <pwd.h>41#include <sys/stat.h>42#endif43 44using namespace llvm;45using namespace llvm::sys;46 47#define ASSERT_NO_ERROR(x)                                                     \48  if (std::error_code ASSERT_NO_ERROR_ec = x) {                                \49    SmallString<128> MessageStorage;                                           \50    raw_svector_ostream Message(MessageStorage);                               \51    Message << #x ": did not return errc::success.\n"                          \52            << "error number: " << ASSERT_NO_ERROR_ec.value() << "\n"          \53            << "error message: " << ASSERT_NO_ERROR_ec.message() << "\n";      \54    GTEST_FATAL_FAILURE_(MessageStorage.c_str());                              \55  } else {                                                                     \56  }57 58#define ASSERT_ERROR(x)                                                        \59  if (!x) {                                                                    \60    SmallString<128> MessageStorage;                                           \61    raw_svector_ostream Message(MessageStorage);                               \62    Message << #x ": did not return a failure error code.\n";                  \63    GTEST_FATAL_FAILURE_(MessageStorage.c_str());                              \64  }65 66namespace {67 68void checkSeparators(StringRef Path) {69#ifdef _WIN3270  char UndesiredSeparator = sys::path::get_separator()[0] == '/' ? '\\' : '/';71  ASSERT_EQ(Path.find(UndesiredSeparator), StringRef::npos);72#endif73}74 75struct FileDescriptorCloser {76  explicit FileDescriptorCloser(int FD) : FD(FD) {}77  ~FileDescriptorCloser() { ::close(FD); }78  int FD;79};80 81TEST(is_style_Style, Works) {82  using namespace llvm::sys::path;83  // Check platform-independent results.84  EXPECT_TRUE(is_style_posix(Style::posix));85  EXPECT_TRUE(is_style_windows(Style::windows));86  EXPECT_TRUE(is_style_windows(Style::windows_slash));87  EXPECT_FALSE(is_style_posix(Style::windows));88  EXPECT_FALSE(is_style_posix(Style::windows_slash));89  EXPECT_FALSE(is_style_windows(Style::posix));90 91  // Check platform-dependent results.92#if defined(_WIN32)93  EXPECT_FALSE(is_style_posix(Style::native));94  EXPECT_TRUE(is_style_windows(Style::native));95#else96  EXPECT_TRUE(is_style_posix(Style::native));97  EXPECT_FALSE(is_style_windows(Style::native));98#endif99}100 101TEST(is_separator, Works) {102  EXPECT_TRUE(path::is_separator('/'));103  EXPECT_FALSE(path::is_separator('\0'));104  EXPECT_FALSE(path::is_separator('-'));105  EXPECT_FALSE(path::is_separator(' '));106 107  EXPECT_TRUE(path::is_separator('\\', path::Style::windows));108  EXPECT_TRUE(path::is_separator('\\', path::Style::windows_slash));109  EXPECT_FALSE(path::is_separator('\\', path::Style::posix));110 111  EXPECT_EQ(path::is_style_windows(path::Style::native),112            path::is_separator('\\'));113}114 115TEST(get_separator, Works) {116  EXPECT_EQ(path::get_separator(path::Style::posix), "/");117  EXPECT_EQ(path::get_separator(path::Style::windows_backslash), "\\");118  EXPECT_EQ(path::get_separator(path::Style::windows_slash), "/");119}120 121TEST(is_absolute_gnu, Works) {122  // Test tuple <Path, ExpectedPosixValue, ExpectedWindowsValue>.123  const std::tuple<StringRef, bool, bool> Paths[] = {124      std::make_tuple("", false, false),125      std::make_tuple("/", true, true),126      std::make_tuple("/foo", true, true),127      std::make_tuple("\\", false, true),128      std::make_tuple("\\foo", false, true),129      std::make_tuple("foo", false, false),130      std::make_tuple("c", false, false),131      std::make_tuple("c:", false, true),132      std::make_tuple("c:\\", false, true),133      std::make_tuple("!:", false, true),134      std::make_tuple("xx:", false, false),135      std::make_tuple("c:abc\\", false, true),136      std::make_tuple(":", false, false)};137 138  for (const auto &Path : Paths) {139    EXPECT_EQ(path::is_absolute_gnu(std::get<0>(Path), path::Style::posix),140              std::get<1>(Path));141    EXPECT_EQ(path::is_absolute_gnu(std::get<0>(Path), path::Style::windows),142              std::get<2>(Path));143 144    constexpr int Native = is_style_posix(path::Style::native) ? 1 : 2;145    EXPECT_EQ(path::is_absolute_gnu(std::get<0>(Path), path::Style::native),146              std::get<Native>(Path));147  }148}149 150TEST(Support, Path) {151  SmallVector<StringRef, 40> paths;152  paths.push_back("");153  paths.push_back(".");154  paths.push_back("..");155  paths.push_back("foo");156  paths.push_back("/");157  paths.push_back("/foo");158  paths.push_back("foo/");159  paths.push_back("/foo/");160  paths.push_back("foo/bar");161  paths.push_back("/foo/bar");162  paths.push_back("//net");163  paths.push_back("//net/");164  paths.push_back("//net/foo");165  paths.push_back("///foo///");166  paths.push_back("///foo///bar");167  paths.push_back("/.");168  paths.push_back("./");169  paths.push_back("/..");170  paths.push_back("../");171  paths.push_back("foo/.");172  paths.push_back("foo/..");173  paths.push_back("foo/./");174  paths.push_back("foo/./bar");175  paths.push_back("foo/..");176  paths.push_back("foo/../");177  paths.push_back("foo/../bar");178  paths.push_back("c:");179  paths.push_back("c:/");180  paths.push_back("c:foo");181  paths.push_back("c:/foo");182  paths.push_back("c:foo/");183  paths.push_back("c:/foo/");184  paths.push_back("c:/foo/bar");185  paths.push_back("prn:");186  paths.push_back("c:\\");187  paths.push_back("c:foo");188  paths.push_back("c:\\foo");189  paths.push_back("c:foo\\");190  paths.push_back("c:\\foo\\");191  paths.push_back("c:\\foo/");192  paths.push_back("c:/foo\\bar");193  paths.push_back(":");194 195  for (SmallVector<StringRef, 40>::const_iterator i = paths.begin(),196                                                  e = paths.end();197                                                  i != e;198                                                  ++i) {199    SCOPED_TRACE(*i);200    SmallVector<StringRef, 5> ComponentStack;201    for (sys::path::const_iterator ci = sys::path::begin(*i),202                                   ce = sys::path::end(*i);203                                   ci != ce;204                                   ++ci) {205      EXPECT_FALSE(ci->empty());206      ComponentStack.push_back(*ci);207    }208 209    SmallVector<StringRef, 5> ReverseComponentStack;210    for (sys::path::reverse_iterator ci = sys::path::rbegin(*i),211                                     ce = sys::path::rend(*i);212                                     ci != ce;213                                     ++ci) {214      EXPECT_FALSE(ci->empty());215      ReverseComponentStack.push_back(*ci);216    }217    std::reverse(ReverseComponentStack.begin(), ReverseComponentStack.end());218    EXPECT_THAT(ComponentStack, testing::ContainerEq(ReverseComponentStack));219 220    // Crash test most of the API - since we're iterating over all of our paths221    // here there isn't really anything reasonable to assert on in the results.222    (void)path::has_root_path(*i);223    (void)path::root_path(*i);224    (void)path::has_root_name(*i);225    (void)path::root_name(*i);226    (void)path::has_root_directory(*i);227    (void)path::root_directory(*i);228    (void)path::has_parent_path(*i);229    (void)path::parent_path(*i);230    (void)path::has_filename(*i);231    (void)path::filename(*i);232    (void)path::has_stem(*i);233    (void)path::stem(*i);234    (void)path::has_extension(*i);235    (void)path::extension(*i);236    (void)path::is_absolute(*i);237    (void)path::is_absolute_gnu(*i);238    (void)path::is_relative(*i);239 240    SmallString<128> temp_store;241    temp_store = *i;242    ASSERT_NO_ERROR(fs::make_absolute(temp_store));243    temp_store = *i;244    path::remove_filename(temp_store);245 246    temp_store = *i;247    path::replace_extension(temp_store, "ext");248    StringRef filename(temp_store.begin(), temp_store.size()), stem, ext;249    stem = path::stem(filename);250    ext  = path::extension(filename);251    EXPECT_EQ(*sys::path::rbegin(filename), (stem + ext).str());252 253    path::native(*i, temp_store);254  }255 256  {257    SmallString<32> Relative("foo.cpp");258    path::make_absolute("/root", Relative);259    Relative[5] = '/'; // Fix up windows paths.260    ASSERT_EQ("/root/foo.cpp", Relative);261  }262 263  {264    SmallString<32> Relative("foo.cpp");265    path::make_absolute("//root", Relative);266    Relative[6] = '/'; // Fix up windows paths.267    ASSERT_EQ("//root/foo.cpp", Relative);268  }269}270 271TEST(Support, PathRoot) {272  ASSERT_EQ(path::root_name("//net/hello", path::Style::posix).str(), "//net");273  ASSERT_EQ(path::root_name("c:/hello", path::Style::posix).str(), "");274  ASSERT_EQ(path::root_name("c:/hello", path::Style::windows).str(), "c:");275  ASSERT_EQ(path::root_name("/hello", path::Style::posix).str(), "");276 277  ASSERT_EQ(path::root_directory("/goo/hello", path::Style::posix).str(), "/");278  ASSERT_EQ(path::root_directory("c:/hello", path::Style::windows).str(), "/");279  ASSERT_EQ(path::root_directory("d/file.txt", path::Style::posix).str(), "");280  ASSERT_EQ(path::root_directory("d/file.txt", path::Style::windows).str(), "");281 282  SmallVector<StringRef, 40> paths;283  paths.push_back("");284  paths.push_back(".");285  paths.push_back("..");286  paths.push_back("foo");287  paths.push_back("/");288  paths.push_back("/foo");289  paths.push_back("foo/");290  paths.push_back("/foo/");291  paths.push_back("foo/bar");292  paths.push_back("/foo/bar");293  paths.push_back("//net");294  paths.push_back("//net/");295  paths.push_back("//net/foo");296  paths.push_back("///foo///");297  paths.push_back("///foo///bar");298  paths.push_back("/.");299  paths.push_back("./");300  paths.push_back("/..");301  paths.push_back("../");302  paths.push_back("foo/.");303  paths.push_back("foo/..");304  paths.push_back("foo/./");305  paths.push_back("foo/./bar");306  paths.push_back("foo/..");307  paths.push_back("foo/../");308  paths.push_back("foo/../bar");309  paths.push_back("c:");310  paths.push_back("c:/");311  paths.push_back("c:foo");312  paths.push_back("c:/foo");313  paths.push_back("c:foo/");314  paths.push_back("c:/foo/");315  paths.push_back("c:/foo/bar");316  paths.push_back("prn:");317  paths.push_back("c:\\");318  paths.push_back("c:foo");319  paths.push_back("c:\\foo");320  paths.push_back("c:foo\\");321  paths.push_back("c:\\foo\\");322  paths.push_back("c:\\foo/");323  paths.push_back("c:/foo\\bar");324 325  for (StringRef p : paths) {326    ASSERT_EQ(327      path::root_name(p, path::Style::posix).str() + path::root_directory(p, path::Style::posix).str(),328      path::root_path(p, path::Style::posix).str());329 330    ASSERT_EQ(331      path::root_name(p, path::Style::windows).str() + path::root_directory(p, path::Style::windows).str(),332      path::root_path(p, path::Style::windows).str());333  }334}335 336TEST(Support, FilenameParent) {337  EXPECT_EQ("/", path::filename("/"));338  EXPECT_EQ("", path::parent_path("/"));339 340  EXPECT_EQ("\\", path::filename("c:\\", path::Style::windows));341  EXPECT_EQ("c:", path::parent_path("c:\\", path::Style::windows));342 343  EXPECT_EQ("/", path::filename("///"));344  EXPECT_EQ("", path::parent_path("///"));345 346  EXPECT_EQ("\\", path::filename("c:\\\\", path::Style::windows));347  EXPECT_EQ("c:", path::parent_path("c:\\\\", path::Style::windows));348 349  EXPECT_EQ("bar", path::filename("/foo/bar"));350  EXPECT_EQ("/foo", path::parent_path("/foo/bar"));351 352  EXPECT_EQ("foo", path::filename("/foo"));353  EXPECT_EQ("/", path::parent_path("/foo"));354 355  EXPECT_EQ("foo", path::filename("foo"));356  EXPECT_EQ("", path::parent_path("foo"));357 358  EXPECT_EQ(".", path::filename("foo/"));359  EXPECT_EQ("foo", path::parent_path("foo/"));360 361  EXPECT_EQ("//net", path::filename("//net"));362  EXPECT_EQ("", path::parent_path("//net"));363 364  EXPECT_EQ("/", path::filename("//net/"));365  EXPECT_EQ("//net", path::parent_path("//net/"));366 367  EXPECT_EQ("foo", path::filename("//net/foo"));368  EXPECT_EQ("//net/", path::parent_path("//net/foo"));369 370  // These checks are just to make sure we do something reasonable with the371  // paths below. They are not meant to prescribe the one true interpretation of372  // these paths. Other decompositions (e.g. "//" -> "" + "//") are also373  // possible.374  EXPECT_EQ("/", path::filename("//"));375  EXPECT_EQ("", path::parent_path("//"));376 377  EXPECT_EQ("\\", path::filename("\\\\", path::Style::windows));378  EXPECT_EQ("", path::parent_path("\\\\", path::Style::windows));379 380  EXPECT_EQ("\\", path::filename("\\\\\\", path::Style::windows));381  EXPECT_EQ("", path::parent_path("\\\\\\", path::Style::windows));382}383 384static std::vector<StringRef>385GetComponents(StringRef Path, path::Style S = path::Style::native) {386  return {path::begin(Path, S), path::end(Path)};387}388 389TEST(Support, PathIterator) {390  EXPECT_THAT(GetComponents("/foo"), testing::ElementsAre("/", "foo"));391  EXPECT_THAT(GetComponents("/"), testing::ElementsAre("/"));392  EXPECT_THAT(GetComponents("//"), testing::ElementsAre("/"));393  EXPECT_THAT(GetComponents("///"), testing::ElementsAre("/"));394  EXPECT_THAT(GetComponents("c/d/e/foo.txt"),395              testing::ElementsAre("c", "d", "e", "foo.txt"));396  EXPECT_THAT(GetComponents(".c/.d/../."),397              testing::ElementsAre(".c", ".d", "..", "."));398  EXPECT_THAT(GetComponents("/c/d/e/foo.txt"),399              testing::ElementsAre("/", "c", "d", "e", "foo.txt"));400  EXPECT_THAT(GetComponents("/.c/.d/../."),401              testing::ElementsAre("/", ".c", ".d", "..", "."));402  EXPECT_THAT(GetComponents("c:\\c\\e\\foo.txt", path::Style::windows),403              testing::ElementsAre("c:", "\\", "c", "e", "foo.txt"));404  EXPECT_THAT(GetComponents("c:\\c\\e\\foo.txt", path::Style::windows_slash),405              testing::ElementsAre("c:", "\\", "c", "e", "foo.txt"));406  EXPECT_THAT(GetComponents("//net/"), testing::ElementsAre("//net", "/"));407  EXPECT_THAT(GetComponents("//net/c/foo.txt"),408              testing::ElementsAre("//net", "/", "c", "foo.txt"));409}410 411TEST(Support, AbsolutePathIteratorEnd) {412  // Trailing slashes are converted to '.' unless they are part of the root path.413  SmallVector<std::pair<StringRef, path::Style>, 4> Paths;414  Paths.emplace_back("/foo/", path::Style::native);415  Paths.emplace_back("/foo//", path::Style::native);416  Paths.emplace_back("//net/foo/", path::Style::native);417  Paths.emplace_back("c:\\foo\\", path::Style::windows);418 419  for (auto &Path : Paths) {420    SCOPED_TRACE(Path.first);421    StringRef LastComponent = *path::rbegin(Path.first, Path.second);422    EXPECT_EQ(".", LastComponent);423  }424 425  SmallVector<std::pair<StringRef, path::Style>, 3> RootPaths;426  RootPaths.emplace_back("/", path::Style::native);427  RootPaths.emplace_back("//net/", path::Style::native);428  RootPaths.emplace_back("c:\\", path::Style::windows);429  RootPaths.emplace_back("//net//", path::Style::native);430  RootPaths.emplace_back("c:\\\\", path::Style::windows);431 432  for (auto &Path : RootPaths) {433    SCOPED_TRACE(Path.first);434    StringRef LastComponent = *path::rbegin(Path.first, Path.second);435    EXPECT_EQ(1u, LastComponent.size());436    EXPECT_TRUE(path::is_separator(LastComponent[0], Path.second));437  }438}439 440#ifdef _WIN32441std::string getEnvWin(const wchar_t *Var) {442  std::string expected;443  if (wchar_t const *path = ::_wgetenv(Var)) {444    auto pathLen = ::wcslen(path);445    ArrayRef<char> ref{reinterpret_cast<char const *>(path),446                       pathLen * sizeof(wchar_t)};447    convertUTF16ToUTF8String(ref, expected);448    SmallString<32> Buf(expected);449    path::make_preferred(Buf);450    expected.assign(Buf.begin(), Buf.end());451  }452  return expected;453}454#else455// RAII helper to set and restore an environment variable.456class WithEnv {457  const char *Var;458  std::optional<std::string> OriginalValue;459 460public:461  WithEnv(const char *Var, const char *Value) : Var(Var) {462    if (const char *V = ::getenv(Var))463      OriginalValue.emplace(V);464    if (Value)465      ::setenv(Var, Value, 1);466    else467      ::unsetenv(Var);468  }469  ~WithEnv() {470    if (OriginalValue)471      ::setenv(Var, OriginalValue->c_str(), 1);472    else473      ::unsetenv(Var);474  }475};476#endif477 478TEST(Support, HomeDirectory) {479  std::string expected;480#ifdef _WIN32481  expected = getEnvWin(L"USERPROFILE");482#else483  if (char const *path = ::getenv("HOME"))484    expected = path;485#endif486  // Do not try to test it if we don't know what to expect.487  // On Windows we use something better than env vars.488  if (expected.empty())489    GTEST_SKIP();490  SmallString<128> HomeDir;491  auto status = path::home_directory(HomeDir);492  EXPECT_TRUE(status);493  EXPECT_EQ(expected, HomeDir);494}495 496// Apple has their own solution for this.497#if defined(LLVM_ON_UNIX) && !defined(__APPLE__)498TEST(Support, HomeDirectoryWithNoEnv) {499  WithEnv Env("HOME", nullptr);500 501  // Don't run the test if we have nothing to compare against.502  struct passwd *pw = getpwuid(getuid());503  if (!pw || !pw->pw_dir)504    GTEST_SKIP();505  std::string PwDir = pw->pw_dir;506 507  SmallString<128> HomeDir;508  EXPECT_TRUE(path::home_directory(HomeDir));509  EXPECT_EQ(PwDir, HomeDir);510}511 512TEST(Support, ConfigDirectoryWithEnv) {513  WithEnv Env("XDG_CONFIG_HOME", "/xdg/config");514 515  SmallString<128> ConfigDir;516  EXPECT_TRUE(path::user_config_directory(ConfigDir));517  EXPECT_EQ("/xdg/config", ConfigDir);518}519 520TEST(Support, ConfigDirectoryNoEnv) {521  WithEnv Env("XDG_CONFIG_HOME", nullptr);522 523  SmallString<128> Fallback;524  ASSERT_TRUE(path::home_directory(Fallback));525  path::append(Fallback, ".config");526 527  SmallString<128> CacheDir;528  EXPECT_TRUE(path::user_config_directory(CacheDir));529  EXPECT_EQ(Fallback, CacheDir);530}531 532TEST(Support, CacheDirectoryWithEnv) {533  WithEnv Env("XDG_CACHE_HOME", "/xdg/cache");534 535  SmallString<128> CacheDir;536  EXPECT_TRUE(path::cache_directory(CacheDir));537  EXPECT_EQ("/xdg/cache", CacheDir);538}539 540TEST(Support, CacheDirectoryNoEnv) {541  WithEnv Env("XDG_CACHE_HOME", nullptr);542 543  SmallString<128> Fallback;544  ASSERT_TRUE(path::home_directory(Fallback));545  path::append(Fallback, ".cache");546 547  SmallString<128> CacheDir;548  EXPECT_TRUE(path::cache_directory(CacheDir));549  EXPECT_EQ(Fallback, CacheDir);550}551#endif552 553#ifdef __APPLE__554TEST(Support, ConfigDirectory) {555  SmallString<128> Fallback;556  ASSERT_TRUE(path::home_directory(Fallback));557  path::append(Fallback, "Library/Preferences");558 559  SmallString<128> ConfigDir;560  EXPECT_TRUE(path::user_config_directory(ConfigDir));561  EXPECT_EQ(Fallback, ConfigDir);562}563#endif564 565#ifdef _WIN32566TEST(Support, ConfigDirectory) {567  std::string Expected = getEnvWin(L"LOCALAPPDATA");568  // Do not try to test it if we don't know what to expect.569  if (Expected.empty())570    GTEST_SKIP();571  SmallString<128> CacheDir;572  EXPECT_TRUE(path::user_config_directory(CacheDir));573  EXPECT_EQ(Expected, CacheDir);574}575 576TEST(Support, CacheDirectory) {577  std::string Expected = getEnvWin(L"LOCALAPPDATA");578  // Do not try to test it if we don't know what to expect.579  if (Expected.empty())580    GTEST_SKIP();581  SmallString<128> CacheDir;582  EXPECT_TRUE(path::cache_directory(CacheDir));583  EXPECT_EQ(Expected, CacheDir);584}585#endif586 587TEST(Support, TempDirectory) {588  SmallString<32> TempDir;589  path::system_temp_directory(false, TempDir);590  EXPECT_TRUE(!TempDir.empty());591  TempDir.clear();592  path::system_temp_directory(true, TempDir);593  EXPECT_TRUE(!TempDir.empty());594}595 596#ifdef _WIN32597static std::string path2regex(std::string Path) {598  size_t Pos = 0;599  bool Forward = path::get_separator()[0] == '/';600  while ((Pos = Path.find('\\', Pos)) != std::string::npos) {601    if (Forward) {602      Path.replace(Pos, 1, "/");603      Pos += 1;604    } else {605      Path.replace(Pos, 1, "\\\\");606      Pos += 2;607    }608  }609  return Path;610}611 612/// Helper for running temp dir test in separated process. See below.613#define EXPECT_TEMP_DIR(prepare, expected)                                     \614  EXPECT_EXIT(                                                                 \615      {                                                                        \616        prepare;                                                               \617        SmallString<300> TempDir;                                              \618        path::system_temp_directory(true, TempDir);                            \619        raw_os_ostream(std::cerr) << TempDir;                                  \620        std::exit(0);                                                          \621      },                                                                       \622      ::testing::ExitedWithCode(0), path2regex(expected))623 624TEST(SupportDeathTest, TempDirectoryOnWindows) {625  // In this test we want to check how system_temp_directory responds to626  // different values of specific env vars. To prevent corrupting env vars of627  // the current process all checks are done in separated processes.628  EXPECT_TEMP_DIR(_wputenv_s(L"TMP", L"C:\\OtherFolder"), "C:\\OtherFolder");629  EXPECT_TEMP_DIR(_wputenv_s(L"TMP", L"C:/Unix/Path/Separators"),630                  "C:\\Unix\\Path\\Separators");631  EXPECT_TEMP_DIR(_wputenv_s(L"TMP", L"Local Path"), ".+\\Local Path$");632  EXPECT_TEMP_DIR(_wputenv_s(L"TMP", L"F:\\TrailingSep\\"), "F:\\TrailingSep");633  EXPECT_TEMP_DIR(634      _wputenv_s(L"TMP", L"C:\\2\x03C0r-\x00B5\x00B3\\\x2135\x2080"),635      "C:\\2\xCF\x80r-\xC2\xB5\xC2\xB3\\\xE2\x84\xB5\xE2\x82\x80");636 637  // Test $TMP empty, $TEMP set.638  EXPECT_TEMP_DIR(639      {640        _wputenv_s(L"TMP", L"");641        _wputenv_s(L"TEMP", L"C:\\Valid\\Path");642      },643      "C:\\Valid\\Path");644 645  // All related env vars empty646  EXPECT_TEMP_DIR(647  {648    _wputenv_s(L"TMP", L"");649    _wputenv_s(L"TEMP", L"");650    _wputenv_s(L"USERPROFILE", L"");651  },652    "C:\\Temp");653 654  // Test evn var / path with 260 chars.655  SmallString<270> Expected{"C:\\Temp\\AB\\123456789"};656  while (Expected.size() < 260)657    Expected.append("\\DirNameWith19Charss");658  ASSERT_EQ(260U, Expected.size());659  EXPECT_TEMP_DIR(_putenv_s("TMP", Expected.c_str()), Expected.c_str());660}661#endif662 663class FileSystemTest : public testing::Test {664protected:665  /// Unique temporary directory in which all created filesystem entities must666  /// be placed. It is removed at the end of each test (must be empty).667  SmallString<128> TestDirectory;668  SmallString<128> NonExistantFile;669 670  void SetUp() override {671    ASSERT_NO_ERROR(672        fs::createUniqueDirectory("file-system-test", TestDirectory));673    // We don't care about this specific file.674    errs() << "Test Directory: " << TestDirectory << '\n';675    errs().flush();676    NonExistantFile = TestDirectory;677 678    // Even though this value is hardcoded, is a 128-bit GUID, so we should be679    // guaranteed that this file will never exist.680    sys::path::append(NonExistantFile, "1B28B495C16344CB9822E588CD4C3EF0");681  }682 683  void TearDown() override { ASSERT_NO_ERROR(fs::remove(TestDirectory.str())); }684};685 686TEST_F(FileSystemTest, Unique) {687  // Create a temp file.688  int FileDescriptor;689  SmallString<64> TempPath;690  ASSERT_NO_ERROR(691      fs::createTemporaryFile("prefix", "temp", FileDescriptor, TempPath));692 693  // The same file should return an identical unique id.694  fs::UniqueID F1, F2;695  ASSERT_NO_ERROR(fs::getUniqueID(Twine(TempPath), F1));696  ASSERT_NO_ERROR(fs::getUniqueID(Twine(TempPath), F2));697  ASSERT_EQ(F1, F2);698 699  // Different files should return different unique ids.700  int FileDescriptor2;701  SmallString<64> TempPath2;702  ASSERT_NO_ERROR(703      fs::createTemporaryFile("prefix", "temp", FileDescriptor2, TempPath2));704 705  fs::UniqueID D;706  ASSERT_NO_ERROR(fs::getUniqueID(Twine(TempPath2), D));707  ASSERT_NE(D, F1);708  ::close(FileDescriptor2);709 710  ASSERT_NO_ERROR(fs::remove(Twine(TempPath2)));711 712#ifndef _WIN32713  // Two paths representing the same file on disk should still provide the714  // same unique id.  We can test this by making a hard link.715  // FIXME: Our implementation of getUniqueID on Windows doesn't consider hard716  // links to be the same file.717  ASSERT_NO_ERROR(fs::create_link(Twine(TempPath), Twine(TempPath2)));718  fs::UniqueID D2;719  ASSERT_NO_ERROR(fs::getUniqueID(Twine(TempPath2), D2));720  ASSERT_EQ(D2, F1);721#endif722 723  ::close(FileDescriptor);724 725  SmallString<128> Dir1;726  ASSERT_NO_ERROR(727     fs::createUniqueDirectory("dir1", Dir1));728  ASSERT_NO_ERROR(fs::getUniqueID(Dir1.c_str(), F1));729  ASSERT_NO_ERROR(fs::getUniqueID(Dir1.c_str(), F2));730  ASSERT_EQ(F1, F2);731 732  SmallString<128> Dir2;733  ASSERT_NO_ERROR(734     fs::createUniqueDirectory("dir2", Dir2));735  ASSERT_NO_ERROR(fs::getUniqueID(Dir2.c_str(), F2));736  ASSERT_NE(F1, F2);737  ASSERT_NO_ERROR(fs::remove(Dir1));738  ASSERT_NO_ERROR(fs::remove(Dir2));739  ASSERT_NO_ERROR(fs::remove(TempPath2));740  ASSERT_NO_ERROR(fs::remove(TempPath));741}742 743TEST_F(FileSystemTest, RealPath) {744  ASSERT_NO_ERROR(745      fs::create_directories(Twine(TestDirectory) + "/test1/test2/test3"));746  ASSERT_TRUE(fs::exists(Twine(TestDirectory) + "/test1/test2/test3"));747 748  SmallString<64> RealBase;749  SmallString<64> Expected;750  SmallString<64> Actual;751 752  // TestDirectory itself might be under a symlink or have been specified with753  // a different case than the existing temp directory.  In such cases real_path754  // on the concatenated path will differ in the TestDirectory portion from755  // how we specified it.  Make sure to compare against the real_path of the756  // TestDirectory, and not just the value of TestDirectory.757  ASSERT_NO_ERROR(fs::real_path(TestDirectory, RealBase));758  checkSeparators(RealBase);759  path::native(Twine(RealBase) + "/test1/test2", Expected);760 761  ASSERT_NO_ERROR(fs::real_path(762      Twine(TestDirectory) + "/././test1/../test1/test2/./test3/..", Actual));763  checkSeparators(Actual);764 765  EXPECT_EQ(Expected, Actual);766 767  SmallString<64> HomeDir;768 769  // This can fail if $HOME is not set and getpwuid fails.770  bool Result = llvm::sys::path::home_directory(HomeDir);771  if (Result) {772    checkSeparators(HomeDir);773    ASSERT_NO_ERROR(fs::real_path(HomeDir, Expected));774    checkSeparators(Expected);775    ASSERT_NO_ERROR(fs::real_path("~", Actual, true));776    EXPECT_EQ(Expected, Actual);777    ASSERT_NO_ERROR(fs::real_path("~/", Actual, true));778    EXPECT_EQ(Expected, Actual);779  }780 781  ASSERT_NO_ERROR(fs::remove_directories(Twine(TestDirectory) + "/test1"));782}783 784TEST_F(FileSystemTest, ExpandTilde) {785  SmallString<64> Expected;786  SmallString<64> Actual;787  SmallString<64> HomeDir;788 789  // This can fail if $HOME is not set and getpwuid fails.790  bool Result = llvm::sys::path::home_directory(HomeDir);791  if (Result) {792    fs::expand_tilde(HomeDir, Expected);793 794    fs::expand_tilde("~", Actual);795    EXPECT_EQ(Expected, Actual);796 797#ifdef _WIN32798    Expected += "\\foo";799    fs::expand_tilde("~\\foo", Actual);800#else801    Expected += "/foo";802    fs::expand_tilde("~/foo", Actual);803#endif804 805    EXPECT_EQ(Expected, Actual);806  }807}808 809#ifdef LLVM_ON_UNIX810TEST_F(FileSystemTest, RealPathNoReadPerm) {811  SmallString<64> Expanded;812 813  ASSERT_NO_ERROR(814    fs::create_directories(Twine(TestDirectory) + "/noreadperm"));815  ASSERT_TRUE(fs::exists(Twine(TestDirectory) + "/noreadperm"));816 817  fs::setPermissions(Twine(TestDirectory) + "/noreadperm", fs::no_perms);818  fs::setPermissions(Twine(TestDirectory) + "/noreadperm", fs::all_exe);819 820  ASSERT_NO_ERROR(fs::real_path(Twine(TestDirectory) + "/noreadperm", Expanded,821                                false));822 823  ASSERT_NO_ERROR(fs::remove_directories(Twine(TestDirectory) + "/noreadperm"));824}825TEST_F(FileSystemTest, RemoveDirectoriesNoExePerm) {826  ASSERT_NO_ERROR(827      fs::create_directories(Twine(TestDirectory) + "/noexeperm/foo"));828  ASSERT_TRUE(fs::exists(Twine(TestDirectory) + "/noexeperm/foo"));829 830  fs::setPermissions(Twine(TestDirectory) + "/noexeperm",831                     fs::all_read | fs::all_write);832 833  ASSERT_NO_ERROR(fs::remove_directories(Twine(TestDirectory) + "/noexeperm",834                                         /*IgnoreErrors=*/true));835 836  // It's expected that the directory exists, but some environments appear to837  // allow the removal despite missing the 'x' permission, so be flexible.838  if (fs::exists(Twine(TestDirectory) + "/noexeperm")) {839    fs::setPermissions(Twine(TestDirectory) + "/noexeperm", fs::all_perms);840    ASSERT_NO_ERROR(fs::remove_directories(Twine(TestDirectory) + "/noexeperm",841                                           /*IgnoreErrors=*/false));842  }843}844#endif845 846 847TEST_F(FileSystemTest, TempFileKeepDiscard) {848  // We can keep then discard.849  auto TempFileOrError = fs::TempFile::create(TestDirectory + "/test-%%%%");850  ASSERT_TRUE((bool)TempFileOrError);851  fs::TempFile File = std::move(*TempFileOrError);852  ASSERT_EQ(-1, TempFileOrError->FD);853  ASSERT_FALSE((bool)File.keep(TestDirectory + "/keep"));854  ASSERT_FALSE((bool)File.discard());855  ASSERT_TRUE(fs::exists(TestDirectory + "/keep"));856  ASSERT_NO_ERROR(fs::remove(TestDirectory + "/keep"));857}858 859TEST_F(FileSystemTest, TempFileDiscardDiscard) {860  // We can discard twice.861  auto TempFileOrError = fs::TempFile::create(TestDirectory + "/test-%%%%");862  ASSERT_TRUE((bool)TempFileOrError);863  fs::TempFile File = std::move(*TempFileOrError);864  ASSERT_EQ(-1, TempFileOrError->FD);865  ASSERT_FALSE((bool)File.discard());866  ASSERT_FALSE((bool)File.discard());867  ASSERT_FALSE(fs::exists(TestDirectory + "/keep"));868}869 870TEST_F(FileSystemTest, TempFiles) {871  // Create a temp file.872  int FileDescriptor;873  SmallString<64> TempPath;874  ASSERT_NO_ERROR(875      fs::createTemporaryFile("prefix", "temp", FileDescriptor, TempPath));876 877  // Make sure it exists.878  ASSERT_TRUE(sys::fs::exists(Twine(TempPath)));879 880  // Create another temp tile.881  int FD2;882  SmallString<64> TempPath2;883  ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "temp", FD2, TempPath2));884  ASSERT_TRUE(TempPath2.ends_with(".temp"));885  ASSERT_NE(TempPath.str(), TempPath2.str());886 887  fs::file_status A, B;888  ASSERT_NO_ERROR(fs::status(Twine(TempPath), A));889  ASSERT_NO_ERROR(fs::status(Twine(TempPath2), B));890  EXPECT_FALSE(fs::equivalent(A, B));891 892  ::close(FD2);893 894  // Remove Temp2.895  ASSERT_NO_ERROR(fs::remove(Twine(TempPath2)));896  ASSERT_NO_ERROR(fs::remove(Twine(TempPath2)));897  ASSERT_EQ(fs::remove(Twine(TempPath2), false),898            errc::no_such_file_or_directory);899 900  std::error_code EC = fs::status(TempPath2.c_str(), B);901  EXPECT_EQ(EC, errc::no_such_file_or_directory);902  EXPECT_EQ(B.type(), fs::file_type::file_not_found);903 904  // Make sure Temp2 doesn't exist.905  ASSERT_EQ(fs::access(Twine(TempPath2), sys::fs::AccessMode::Exist),906            errc::no_such_file_or_directory);907 908  SmallString<64> TempPath3;909  ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "", TempPath3));910  ASSERT_FALSE(TempPath3.ends_with("."));911  FileRemover Cleanup3(TempPath3);912 913  // Create a hard link to Temp1.914  ASSERT_NO_ERROR(fs::create_link(Twine(TempPath), Twine(TempPath2)));915#ifndef _WIN32916  // FIXME: Our implementation of equivalent() on Windows doesn't consider hard917  // links to be the same file.918  bool equal;919  ASSERT_NO_ERROR(fs::equivalent(Twine(TempPath), Twine(TempPath2), equal));920  EXPECT_TRUE(equal);921  ASSERT_NO_ERROR(fs::status(Twine(TempPath), A));922  ASSERT_NO_ERROR(fs::status(Twine(TempPath2), B));923  EXPECT_TRUE(fs::equivalent(A, B));924#endif925 926  // Remove Temp1.927  ::close(FileDescriptor);928  ASSERT_NO_ERROR(fs::remove(Twine(TempPath)));929 930  // Remove the hard link.931  ASSERT_NO_ERROR(fs::remove(Twine(TempPath2)));932 933  // Make sure Temp1 doesn't exist.934  ASSERT_EQ(fs::access(Twine(TempPath), sys::fs::AccessMode::Exist),935            errc::no_such_file_or_directory);936 937#ifdef _WIN32938  // Path name > 260 chars should get an error.939  const char *Path270 =940    "abcdefghijklmnopqrstuvwxyz9abcdefghijklmnopqrstuvwxyz8"941    "abcdefghijklmnopqrstuvwxyz7abcdefghijklmnopqrstuvwxyz6"942    "abcdefghijklmnopqrstuvwxyz5abcdefghijklmnopqrstuvwxyz4"943    "abcdefghijklmnopqrstuvwxyz3abcdefghijklmnopqrstuvwxyz2"944    "abcdefghijklmnopqrstuvwxyz1abcdefghijklmnopqrstuvwxyz0";945  EXPECT_EQ(fs::createUniqueFile(Path270, FileDescriptor, TempPath),946            errc::invalid_argument);947  // Relative path < 247 chars, no problem.948  const char *Path216 =949    "abcdefghijklmnopqrstuvwxyz7abcdefghijklmnopqrstuvwxyz6"950    "abcdefghijklmnopqrstuvwxyz5abcdefghijklmnopqrstuvwxyz4"951    "abcdefghijklmnopqrstuvwxyz3abcdefghijklmnopqrstuvwxyz2"952    "abcdefghijklmnopqrstuvwxyz1abcdefghijklmnopqrstuvwxyz0";953  ASSERT_NO_ERROR(fs::createTemporaryFile(Path216, "", TempPath));954  ASSERT_NO_ERROR(fs::remove(Twine(TempPath)));955#endif956}957 958TEST_F(FileSystemTest, TempFileCollisions) {959  SmallString<128> TestDirectory;960  ASSERT_NO_ERROR(961      fs::createUniqueDirectory("CreateUniqueFileTest", TestDirectory));962  FileRemover Cleanup(TestDirectory);963  SmallString<128> Model = TestDirectory;964  path::append(Model, "%.tmp");965  std::vector<fs::TempFile> TempFiles;966 967  auto TryCreateTempFile = [&]() {968    Expected<fs::TempFile> T = fs::TempFile::create(Model);969    if (T) {970      TempFiles.push_back(std::move(*T));971      return true;972    } else {973      logAllUnhandledErrors(T.takeError(), errs(),974                            "Failed to create temporary file: ");975      return false;976    }977  };978 979  // Our single-character template allows for 16 unique names. Check that980  // calling TryCreateTempFile repeatedly results in 16 successes.981  // Because the test depends on random numbers, it could theoretically fail.982  // However, the probability of this happening is tiny: with 32 calls, each983  // of which will retry up to 128 times, to not get a given digit we would984  // have to fail at least 15 + 17 * 128 = 2191 attempts. The probability of985  // 2191 attempts not producing a given hexadecimal digit is986  // (1 - 1/16) ** 2191 or 3.88e-62.987  int Successes = 0;988  for (int i = 0; i < 32; ++i)989    if (TryCreateTempFile()) ++Successes;990  EXPECT_EQ(Successes, 16);991 992  for (fs::TempFile &T : TempFiles)993    cantFail(T.discard());994}995 996TEST_F(FileSystemTest, CreateDir) {997  ASSERT_NO_ERROR(fs::create_directory(Twine(TestDirectory) + "foo"));998  ASSERT_NO_ERROR(fs::create_directory(Twine(TestDirectory) + "foo"));999  ASSERT_EQ(fs::create_directory(Twine(TestDirectory) + "foo", false),1000            errc::file_exists);1001  ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "foo"));1002 1003#ifdef LLVM_ON_UNIX1004  // Set a 0000 umask so that we can test our directory permissions.1005  mode_t OldUmask = ::umask(0000);1006 1007  fs::file_status Status;1008  ASSERT_NO_ERROR(1009      fs::create_directory(Twine(TestDirectory) + "baz500", false,1010                           fs::perms::owner_read | fs::perms::owner_exe));1011  ASSERT_NO_ERROR(fs::status(Twine(TestDirectory) + "baz500", Status));1012  ASSERT_EQ(Status.permissions() & fs::perms::all_all,1013            fs::perms::owner_read | fs::perms::owner_exe);1014  ASSERT_NO_ERROR(fs::create_directory(Twine(TestDirectory) + "baz777", false,1015                                       fs::perms::all_all));1016  ASSERT_NO_ERROR(fs::status(Twine(TestDirectory) + "baz777", Status));1017  ASSERT_EQ(Status.permissions() & fs::perms::all_all, fs::perms::all_all);1018 1019  // Restore umask to be safe.1020  ::umask(OldUmask);1021#endif1022 1023#ifdef _WIN321024  // Prove that create_directories() can handle a pathname > 248 characters,1025  // which is the documented limit for CreateDirectory().1026  // (248 is MAX_PATH subtracting room for an 8.3 filename.)1027  // Generate a directory path guaranteed to fall into that range.1028  size_t TmpLen = TestDirectory.size();1029  const char *OneDir = "\\123456789";1030  size_t OneDirLen = strlen(OneDir);1031  ASSERT_LT(OneDirLen, 12U);1032  size_t NLevels = ((248 - TmpLen) / OneDirLen) + 1;1033  SmallString<260> LongDir(TestDirectory);1034  for (size_t I = 0; I < NLevels; ++I)1035    LongDir.append(OneDir);1036  ASSERT_NO_ERROR(fs::create_directories(Twine(LongDir)));1037  ASSERT_NO_ERROR(fs::create_directories(Twine(LongDir)));1038  ASSERT_EQ(fs::create_directories(Twine(LongDir), false),1039            errc::file_exists);1040  // Tidy up, "recursively" removing the directories.1041  StringRef ThisDir(LongDir);1042  for (size_t J = 0; J < NLevels; ++J) {1043    ASSERT_NO_ERROR(fs::remove(ThisDir));1044    ThisDir = path::parent_path(ThisDir);1045  }1046 1047  // Also verify that paths with Unix separators are handled correctly.1048  std::string LongPathWithUnixSeparators(TestDirectory.str());1049  // Add at least one subdirectory to TestDirectory, and replace slashes with1050  // backslashes1051  do {1052    LongPathWithUnixSeparators.append("/DirNameWith19Charss");1053  } while (LongPathWithUnixSeparators.size() < 260);1054  llvm::replace(LongPathWithUnixSeparators, '\\', '/');1055  ASSERT_NO_ERROR(fs::create_directories(Twine(LongPathWithUnixSeparators)));1056  // cleanup1057  ASSERT_NO_ERROR(fs::remove_directories(Twine(TestDirectory) +1058                                         "/DirNameWith19Charss"));1059 1060  // Similarly for a relative pathname.  Need to set the current directory to1061  // TestDirectory so that the one we create ends up in the right place.1062  char PreviousDir[260];1063  size_t PreviousDirLen = ::GetCurrentDirectoryA(260, PreviousDir);1064  ASSERT_GT(PreviousDirLen, 0U);1065  ASSERT_LT(PreviousDirLen, 260U);1066  ASSERT_NE(::SetCurrentDirectoryA(TestDirectory.c_str()), 0);1067  LongDir.clear();1068  // Generate a relative directory name with absolute length > 248.1069  size_t LongDirLen = 249 - TestDirectory.size();1070  LongDir.assign(LongDirLen, 'a');1071  ASSERT_NO_ERROR(fs::create_directory(Twine(LongDir)));1072  // While we're here, prove that .. and . handling works in these long paths.1073  const char *DotDotDirs = "\\..\\.\\b";1074  LongDir.append(DotDotDirs);1075  ASSERT_NO_ERROR(fs::create_directory("b"));1076  ASSERT_EQ(fs::create_directory(Twine(LongDir), false), errc::file_exists);1077  // And clean up.1078  ASSERT_NO_ERROR(fs::remove("b"));1079  ASSERT_NO_ERROR(fs::remove(1080    Twine(LongDir.substr(0, LongDir.size() - strlen(DotDotDirs)))));1081  ASSERT_NE(::SetCurrentDirectoryA(PreviousDir), 0);1082#endif1083}1084 1085TEST_F(FileSystemTest, DirectoryIteration) {1086  std::error_code ec;1087  for (fs::directory_iterator i(".", ec), e; i != e; i.increment(ec))1088    ASSERT_NO_ERROR(ec);1089 1090  // Create a known hierarchy to recurse over.1091  ASSERT_NO_ERROR(1092      fs::create_directories(Twine(TestDirectory) + "/recursive/a0/aa1"));1093  ASSERT_NO_ERROR(1094      fs::create_directories(Twine(TestDirectory) + "/recursive/a0/ab1"));1095  ASSERT_NO_ERROR(fs::create_directories(Twine(TestDirectory) +1096                                         "/recursive/dontlookhere/da1"));1097  ASSERT_NO_ERROR(1098      fs::create_directories(Twine(TestDirectory) + "/recursive/z0/za1"));1099  ASSERT_NO_ERROR(1100      fs::create_directories(Twine(TestDirectory) + "/recursive/pop/p1"));1101  typedef std::vector<std::string> v_t;1102  v_t visited;1103  for (fs::recursive_directory_iterator i(Twine(TestDirectory)1104         + "/recursive", ec), e; i != e; i.increment(ec)){1105    ASSERT_NO_ERROR(ec);1106    if (path::filename(i->path()) == "p1") {1107      i.pop();1108      // FIXME: recursive_directory_iterator should be more robust.1109      if (i == e) break;1110    }1111    if (path::filename(i->path()) == "dontlookhere")1112      i.no_push();1113    visited.push_back(std::string(path::filename(i->path())));1114  }1115  v_t::const_iterator a0 = find(visited, "a0");1116  v_t::const_iterator aa1 = find(visited, "aa1");1117  v_t::const_iterator ab1 = find(visited, "ab1");1118  v_t::const_iterator dontlookhere = find(visited, "dontlookhere");1119  v_t::const_iterator da1 = find(visited, "da1");1120  v_t::const_iterator z0 = find(visited, "z0");1121  v_t::const_iterator za1 = find(visited, "za1");1122  v_t::const_iterator pop = find(visited, "pop");1123  v_t::const_iterator p1 = find(visited, "p1");1124 1125  // Make sure that each path was visited correctly.1126  ASSERT_NE(a0, visited.end());1127  ASSERT_NE(aa1, visited.end());1128  ASSERT_NE(ab1, visited.end());1129  ASSERT_NE(dontlookhere, visited.end());1130  ASSERT_EQ(da1, visited.end()); // Not visited.1131  ASSERT_NE(z0, visited.end());1132  ASSERT_NE(za1, visited.end());1133  ASSERT_NE(pop, visited.end());1134  ASSERT_EQ(p1, visited.end()); // Not visited.1135 1136  // Make sure that parents were visited before children. No other ordering1137  // guarantees can be made across siblings.1138  ASSERT_LT(a0, aa1);1139  ASSERT_LT(a0, ab1);1140  ASSERT_LT(z0, za1);1141 1142  ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/a0/aa1"));1143  ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/a0/ab1"));1144  ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/a0"));1145  ASSERT_NO_ERROR(1146      fs::remove(Twine(TestDirectory) + "/recursive/dontlookhere/da1"));1147  ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/dontlookhere"));1148  ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/pop/p1"));1149  ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/pop"));1150  ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/z0/za1"));1151  ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/z0"));1152  ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive"));1153 1154  // Test recursive_directory_iterator level()1155  ASSERT_NO_ERROR(1156      fs::create_directories(Twine(TestDirectory) + "/reclevel/a/b/c"));1157  fs::recursive_directory_iterator I(Twine(TestDirectory) + "/reclevel", ec), E;1158  for (int l = 0; I != E; I.increment(ec), ++l) {1159    ASSERT_NO_ERROR(ec);1160    EXPECT_EQ(I.level(), l);1161  }1162  EXPECT_EQ(I, E);1163  ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/reclevel/a/b/c"));1164  ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/reclevel/a/b"));1165  ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/reclevel/a"));1166  ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/reclevel"));1167}1168 1169TEST_F(FileSystemTest, DirectoryNotExecutable) {1170  ASSERT_EQ(fs::access(TestDirectory, sys::fs::AccessMode::Execute),1171            errc::permission_denied);1172}1173 1174#ifdef LLVM_ON_UNIX1175TEST_F(FileSystemTest, BrokenSymlinkDirectoryIteration) {1176  // Create a known hierarchy to recurse over.1177  ASSERT_NO_ERROR(fs::create_directories(Twine(TestDirectory) + "/symlink"));1178  ASSERT_NO_ERROR(1179      fs::create_link("no_such_file", Twine(TestDirectory) + "/symlink/a"));1180  ASSERT_NO_ERROR(1181      fs::create_directories(Twine(TestDirectory) + "/symlink/b/bb"));1182  ASSERT_NO_ERROR(1183      fs::create_link("no_such_file", Twine(TestDirectory) + "/symlink/b/ba"));1184  ASSERT_NO_ERROR(1185      fs::create_link("no_such_file", Twine(TestDirectory) + "/symlink/b/bc"));1186  ASSERT_NO_ERROR(1187      fs::create_link("no_such_file", Twine(TestDirectory) + "/symlink/c"));1188  ASSERT_NO_ERROR(1189      fs::create_directories(Twine(TestDirectory) + "/symlink/d/dd/ddd"));1190  ASSERT_NO_ERROR(fs::create_link(Twine(TestDirectory) + "/symlink/d/dd",1191                                  Twine(TestDirectory) + "/symlink/d/da"));1192  ASSERT_NO_ERROR(1193      fs::create_link("no_such_file", Twine(TestDirectory) + "/symlink/e"));1194 1195  typedef std::vector<std::string> v_t;1196  v_t VisitedNonBrokenSymlinks;1197  v_t VisitedBrokenSymlinks;1198  std::error_code ec;1199  using testing::UnorderedElementsAre;1200  using testing::UnorderedElementsAreArray;1201 1202  // Broken symbol links are expected to throw an error.1203  for (fs::directory_iterator i(Twine(TestDirectory) + "/symlink", ec), e;1204       i != e; i.increment(ec)) {1205    ASSERT_NO_ERROR(ec);1206    if (i->status().getError() ==1207        std::make_error_code(std::errc::no_such_file_or_directory)) {1208      VisitedBrokenSymlinks.push_back(std::string(path::filename(i->path())));1209      continue;1210    }1211    VisitedNonBrokenSymlinks.push_back(std::string(path::filename(i->path())));1212  }1213  EXPECT_THAT(VisitedNonBrokenSymlinks, UnorderedElementsAre("b", "d"));1214  VisitedNonBrokenSymlinks.clear();1215 1216  EXPECT_THAT(VisitedBrokenSymlinks, UnorderedElementsAre("a", "c", "e"));1217  VisitedBrokenSymlinks.clear();1218 1219  // Broken symbol links are expected to throw an error.1220  for (fs::recursive_directory_iterator i(1221      Twine(TestDirectory) + "/symlink", ec), e; i != e; i.increment(ec)) {1222    ASSERT_NO_ERROR(ec);1223    if (i->status().getError() ==1224        std::make_error_code(std::errc::no_such_file_or_directory)) {1225      VisitedBrokenSymlinks.push_back(std::string(path::filename(i->path())));1226      continue;1227    }1228    VisitedNonBrokenSymlinks.push_back(std::string(path::filename(i->path())));1229  }1230  EXPECT_THAT(VisitedNonBrokenSymlinks,1231              UnorderedElementsAre("b", "bb", "d", "da", "dd", "ddd", "ddd"));1232  VisitedNonBrokenSymlinks.clear();1233 1234  EXPECT_THAT(VisitedBrokenSymlinks,1235              UnorderedElementsAre("a", "ba", "bc", "c", "e"));1236  VisitedBrokenSymlinks.clear();1237 1238  for (fs::recursive_directory_iterator i(1239      Twine(TestDirectory) + "/symlink", ec, /*follow_symlinks=*/false), e;1240       i != e; i.increment(ec)) {1241    ASSERT_NO_ERROR(ec);1242    if (i->status().getError() ==1243        std::make_error_code(std::errc::no_such_file_or_directory)) {1244      VisitedBrokenSymlinks.push_back(std::string(path::filename(i->path())));1245      continue;1246    }1247    VisitedNonBrokenSymlinks.push_back(std::string(path::filename(i->path())));1248  }1249  EXPECT_THAT(VisitedNonBrokenSymlinks,1250              UnorderedElementsAreArray({"a", "b", "ba", "bb", "bc", "c", "d",1251                                         "da", "dd", "ddd", "e"}));1252  VisitedNonBrokenSymlinks.clear();1253 1254  EXPECT_THAT(VisitedBrokenSymlinks, UnorderedElementsAre());1255  VisitedBrokenSymlinks.clear();1256 1257  ASSERT_NO_ERROR(fs::remove_directories(Twine(TestDirectory) + "/symlink"));1258}1259#endif1260 1261#ifdef _WIN321262TEST_F(FileSystemTest, UTF8ToUTF16DirectoryIteration) {1263  // The Windows filesystem support uses UTF-16 and converts paths from the1264  // input UTF-8. The UTF-16 equivalent of the input path can be shorter in1265  // length.1266 1267  // This test relies on TestDirectory not being so long such that MAX_PATH1268  // would be exceeded (see widenPath). If that were the case, the UTF-161269  // path is likely to be longer than the input.1270  const char *Pi = "\xcf\x80"; // UTF-8 lower case pi.1271  std::string RootDir = (TestDirectory + "/" + Pi).str();1272 1273  // Create test directories.1274  ASSERT_NO_ERROR(fs::create_directories(Twine(RootDir) + "/a"));1275  ASSERT_NO_ERROR(fs::create_directories(Twine(RootDir) + "/b"));1276 1277  std::error_code EC;1278  unsigned Count = 0;1279  for (fs::directory_iterator I(Twine(RootDir), EC), E; I != E;1280       I.increment(EC)) {1281    ASSERT_NO_ERROR(EC);1282    StringRef DirName = path::filename(I->path());1283    EXPECT_TRUE(DirName == "a" || DirName == "b");1284    ++Count;1285  }1286  EXPECT_EQ(Count, 2U);1287 1288  ASSERT_NO_ERROR(fs::remove(Twine(RootDir) + "/a"));1289  ASSERT_NO_ERROR(fs::remove(Twine(RootDir) + "/b"));1290  ASSERT_NO_ERROR(fs::remove(Twine(RootDir)));1291}1292#endif1293 1294TEST_F(FileSystemTest, Remove) {1295  SmallString<64> BaseDir;1296  SmallString<64> Paths[4];1297  int fds[4];1298  ASSERT_NO_ERROR(fs::createUniqueDirectory("fs_remove", BaseDir));1299 1300  ASSERT_NO_ERROR(fs::create_directories(Twine(BaseDir) + "/foo/bar/baz"));1301  ASSERT_NO_ERROR(fs::create_directories(Twine(BaseDir) + "/foo/bar/buzz"));1302  ASSERT_NO_ERROR(fs::createUniqueFile(1303      Twine(BaseDir) + "/foo/bar/baz/%%%%%%.tmp", fds[0], Paths[0]));1304  ASSERT_NO_ERROR(fs::createUniqueFile(1305      Twine(BaseDir) + "/foo/bar/baz/%%%%%%.tmp", fds[1], Paths[1]));1306  ASSERT_NO_ERROR(fs::createUniqueFile(1307      Twine(BaseDir) + "/foo/bar/buzz/%%%%%%.tmp", fds[2], Paths[2]));1308  ASSERT_NO_ERROR(fs::createUniqueFile(1309      Twine(BaseDir) + "/foo/bar/buzz/%%%%%%.tmp", fds[3], Paths[3]));1310 1311  for (int fd : fds)1312    ::close(fd);1313 1314  EXPECT_TRUE(fs::exists(Twine(BaseDir) + "/foo/bar/baz"));1315  EXPECT_TRUE(fs::exists(Twine(BaseDir) + "/foo/bar/buzz"));1316  EXPECT_TRUE(fs::exists(Paths[0]));1317  EXPECT_TRUE(fs::exists(Paths[1]));1318  EXPECT_TRUE(fs::exists(Paths[2]));1319  EXPECT_TRUE(fs::exists(Paths[3]));1320 1321  ASSERT_NO_ERROR(fs::remove_directories("D:/footest"));1322 1323  ASSERT_NO_ERROR(fs::remove_directories(Twine(BaseDir) + "/foo/bar/baz"));1324  ASSERT_FALSE(fs::exists(Twine(BaseDir) + "/foo/bar/baz"));1325 1326  ASSERT_NO_ERROR(fs::remove_directories(BaseDir));1327  ASSERT_FALSE(fs::exists(BaseDir));1328}1329 1330#ifdef _WIN321331TEST_F(FileSystemTest, CarriageReturn) {1332  SmallString<128> FilePathname(TestDirectory);1333  std::error_code EC;1334  path::append(FilePathname, "test");1335 1336  {1337    raw_fd_ostream File(FilePathname, EC, sys::fs::OF_TextWithCRLF);1338    ASSERT_NO_ERROR(EC);1339    File << '\n';1340  }1341  {1342    auto Buf = MemoryBuffer::getFile(FilePathname.str());1343    EXPECT_TRUE((bool)Buf);1344    EXPECT_EQ(Buf.get()->getBuffer(), "\r\n");1345  }1346 1347  {1348    raw_fd_ostream File(FilePathname, EC, sys::fs::OF_None);1349    ASSERT_NO_ERROR(EC);1350    File << '\n';1351  }1352  {1353    auto Buf = MemoryBuffer::getFile(FilePathname.str());1354    EXPECT_TRUE((bool)Buf);1355    EXPECT_EQ(Buf.get()->getBuffer(), "\n");1356  }1357  ASSERT_NO_ERROR(fs::remove(Twine(FilePathname)));1358}1359#endif1360 1361TEST_F(FileSystemTest, Resize) {1362  int FD;1363  SmallString<64> TempPath;1364  ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "temp", FD, TempPath));1365  ASSERT_NO_ERROR(fs::resize_file(FD, 123));1366  fs::file_status Status;1367  ASSERT_NO_ERROR(fs::status(FD, Status));1368  ASSERT_EQ(Status.getSize(), 123U);1369  ::close(FD);1370  ASSERT_NO_ERROR(fs::remove(TempPath));1371}1372 1373TEST_F(FileSystemTest, ResizeBeforeMapping) {1374  // Create a temp file.1375  int FD;1376  SmallString<64> TempPath;1377  ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "temp", FD, TempPath));1378  ASSERT_NO_ERROR(fs::resize_file_before_mapping_readwrite(FD, 123));1379 1380  // Map in temp file. On Windows, fs::resize_file_before_mapping_readwrite is1381  // a no-op and the mapping itself will resize the file.1382  std::error_code EC;1383  {1384    fs::mapped_file_region mfr(fs::convertFDToNativeFile(FD),1385                               fs::mapped_file_region::readwrite, 123, 0, EC);1386    ASSERT_NO_ERROR(EC);1387    // Unmap temp file1388  }1389 1390  // Check the size.1391  fs::file_status Status;1392  ASSERT_NO_ERROR(fs::status(FD, Status));1393  ASSERT_EQ(Status.getSize(), 123U);1394  ::close(FD);1395  ASSERT_NO_ERROR(fs::remove(TempPath));1396}1397 1398TEST_F(FileSystemTest, MD5) {1399  int FD;1400  SmallString<64> TempPath;1401  ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "temp", FD, TempPath));1402  StringRef Data("abcdefghijklmnopqrstuvwxyz");1403  ASSERT_EQ(write(FD, Data.data(), Data.size()), static_cast<ssize_t>(Data.size()));1404  lseek(FD, 0, SEEK_SET);1405  auto Hash = fs::md5_contents(FD);1406  ::close(FD);1407  ASSERT_NO_ERROR(Hash.getError());1408 1409  EXPECT_STREQ("c3fcd3d76192e4007dfb496cca67e13b", Hash->digest().c_str());1410}1411 1412TEST_F(FileSystemTest, FileMapping) {1413  // Create a temp file.1414  int FileDescriptor;1415  SmallString<64> TempPath;1416  ASSERT_NO_ERROR(1417      fs::createTemporaryFile("prefix", "temp", FileDescriptor, TempPath));1418  unsigned Size = 4096;1419  ASSERT_NO_ERROR(1420      fs::resize_file_before_mapping_readwrite(FileDescriptor, Size));1421 1422  // Map in temp file and add some content1423  std::error_code EC;1424  StringRef Val("hello there");1425  fs::mapped_file_region MaybeMFR;1426  EXPECT_FALSE(MaybeMFR);1427  {1428    fs::mapped_file_region mfr(fs::convertFDToNativeFile(FileDescriptor),1429                               fs::mapped_file_region::readwrite, Size, 0, EC);1430    ASSERT_NO_ERROR(EC);1431    llvm::copy(Val, mfr.data());1432    // Explicitly add a 0.1433    mfr.data()[Val.size()] = 0;1434 1435    // Move it out of the scope and confirm mfr is reset.1436    MaybeMFR = std::move(mfr);1437    EXPECT_FALSE(mfr);1438#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST1439    EXPECT_DEATH(mfr.data(), "Mapping failed but used anyway!");1440    EXPECT_DEATH(mfr.size(), "Mapping failed but used anyway!");1441#endif1442  }1443 1444  // Check that the moved-to region is still valid.1445  EXPECT_EQ(Val, StringRef(MaybeMFR.data()));1446  EXPECT_EQ(Size, MaybeMFR.size());1447 1448  // Unmap temp file.1449  MaybeMFR.unmap();1450 1451  ASSERT_EQ(close(FileDescriptor), 0);1452 1453  // Map it back in read-only1454  {1455    int FD;1456    EC = fs::openFileForRead(Twine(TempPath), FD);1457    ASSERT_NO_ERROR(EC);1458    fs::mapped_file_region mfr(fs::convertFDToNativeFile(FD),1459                               fs::mapped_file_region::readonly, Size, 0, EC);1460    ASSERT_NO_ERROR(EC);1461 1462    // Verify content1463    EXPECT_EQ(StringRef(mfr.const_data()), Val);1464 1465    // Unmap temp file1466    fs::mapped_file_region m(fs::convertFDToNativeFile(FD),1467                             fs::mapped_file_region::readonly, Size, 0, EC);1468    ASSERT_NO_ERROR(EC);1469    ASSERT_EQ(close(FD), 0);1470  }1471  ASSERT_NO_ERROR(fs::remove(TempPath));1472}1473 1474TEST_F(FileSystemTest, FileMappingSync) {1475  // Create a temp file.1476  SmallString<0> TempPath(TestDirectory);1477  sys::path::append(TempPath, "test-%%%%");1478  auto TempFileOrError = fs::TempFile::create(TempPath);1479  ASSERT_TRUE((bool)TempFileOrError);1480  fs::TempFile File = std::move(*TempFileOrError);1481  StringRef Content("hello there");1482  std::string FileName = File.TmpName;1483  ASSERT_NO_ERROR(1484      fs::resize_file_before_mapping_readwrite(File.FD, Content.size()));1485  {1486    // Map in the file and write some content.1487    std::error_code EC;1488    fs::mapped_file_region MFR(fs::convertFDToNativeFile(File.FD),1489                               fs::mapped_file_region::readwrite,1490                               Content.size(), 0, EC);1491 1492    // Keep the file so it can be read.1493    ASSERT_FALSE((bool)File.keep());1494 1495    // Write content through mapped memory.1496    ASSERT_NO_ERROR(EC);1497    llvm::copy(Content, MFR.data());1498 1499    // Synchronize to file system.1500    ASSERT_FALSE((bool)MFR.sync());1501 1502    // Check the file content using file IO APIs.1503    auto Buffer = MemoryBuffer::getFile(FileName);1504    ASSERT_TRUE((bool)Buffer);1505    ASSERT_EQ(Content, Buffer->get()->getBuffer());1506  }1507  // Manually remove the test file.1508  ASSERT_FALSE((bool)fs::remove(FileName));1509}1510 1511TEST(Support, NormalizePath) {1512  //                           Input,        Expected Win, Expected Posix1513  using TestTuple = std::tuple<const char *, const char *, const char *>;1514  std::vector<TestTuple> Tests;1515  Tests.emplace_back("a", "a", "a");1516  Tests.emplace_back("a/b", "a\\b", "a/b");1517  Tests.emplace_back("a\\b", "a\\b", "a/b");1518  Tests.emplace_back("a\\\\b", "a\\\\b", "a//b");1519  Tests.emplace_back("\\a", "\\a", "/a");1520  Tests.emplace_back("a\\", "a\\", "a/");1521  Tests.emplace_back("a\\t", "a\\t", "a/t");1522 1523  for (auto &T : Tests) {1524    SmallString<64> Win(std::get<0>(T));1525    SmallString<64> Posix(Win);1526    SmallString<64> WinSlash(Win);1527    path::native(Win, path::Style::windows);1528    path::native(Posix, path::Style::posix);1529    path::native(WinSlash, path::Style::windows_slash);1530    EXPECT_EQ(std::get<1>(T), Win);1531    EXPECT_EQ(std::get<2>(T), Posix);1532    EXPECT_EQ(std::get<2>(T), WinSlash);1533  }1534 1535  for (auto &T : Tests) {1536    SmallString<64> WinBackslash(std::get<0>(T));1537    SmallString<64> Posix(WinBackslash);1538    SmallString<64> WinSlash(WinBackslash);1539    path::make_preferred(WinBackslash, path::Style::windows_backslash);1540    path::make_preferred(Posix, path::Style::posix);1541    path::make_preferred(WinSlash, path::Style::windows_slash);1542    EXPECT_EQ(std::get<1>(T), WinBackslash);1543    EXPECT_EQ(std::get<0>(T), Posix); // Posix remains unchanged here1544    EXPECT_EQ(std::get<2>(T), WinSlash);1545  }1546 1547#if defined(_WIN32)1548  SmallString<64> PathHome;1549  path::home_directory(PathHome);1550 1551  const char *Path7a = "~/aaa";1552  SmallString<64> Path7(Path7a);1553  path::native(Path7, path::Style::windows_backslash);1554  EXPECT_TRUE(Path7.ends_with("\\aaa"));1555  EXPECT_TRUE(Path7.starts_with(PathHome));1556  EXPECT_EQ(Path7.size(), PathHome.size() + strlen(Path7a + 1));1557  Path7 = Path7a;1558  path::native(Path7, path::Style::windows_slash);1559  EXPECT_TRUE(Path7.ends_with("/aaa"));1560  EXPECT_TRUE(Path7.starts_with(PathHome));1561  EXPECT_EQ(Path7.size(), PathHome.size() + strlen(Path7a + 1));1562 1563  const char *Path8a = "~";1564  SmallString<64> Path8(Path8a);1565  path::native(Path8);1566  EXPECT_EQ(Path8, PathHome);1567 1568  const char *Path9a = "~aaa";1569  SmallString<64> Path9(Path9a);1570  path::native(Path9);1571  EXPECT_EQ(Path9, "~aaa");1572 1573  const char *Path10a = "aaa/~/b";1574  SmallString<64> Path10(Path10a);1575  path::native(Path10, path::Style::windows_backslash);1576  EXPECT_EQ(Path10, "aaa\\~\\b");1577#endif1578}1579 1580TEST(Support, RemoveLeadingDotSlash) {1581  StringRef Path1("././/foolz/wat");1582  StringRef Path2("./////");1583 1584  Path1 = path::remove_leading_dotslash(Path1);1585  EXPECT_EQ(Path1, "foolz/wat");1586  Path2 = path::remove_leading_dotslash(Path2);1587  EXPECT_EQ(Path2, "");1588}1589 1590static std::string remove_dots(StringRef path, bool remove_dot_dot,1591                               path::Style style) {1592  SmallString<256> buffer(path);1593  path::remove_dots(buffer, remove_dot_dot, style);1594  return std::string(buffer.str());1595}1596 1597TEST(Support, RemoveDots) {1598  EXPECT_EQ("foolz\\wat",1599            remove_dots(".\\.\\\\foolz\\wat", false, path::Style::windows));1600  EXPECT_EQ("", remove_dots(".\\\\\\\\\\", false, path::Style::windows));1601 1602  EXPECT_EQ("a\\..\\b\\c",1603            remove_dots(".\\a\\..\\b\\c", false, path::Style::windows));1604  EXPECT_EQ("b\\c", remove_dots(".\\a\\..\\b\\c", true, path::Style::windows));1605  EXPECT_EQ("c", remove_dots(".\\.\\c", true, path::Style::windows));1606  EXPECT_EQ("..\\a\\c",1607            remove_dots("..\\a\\b\\..\\c", true, path::Style::windows));1608  EXPECT_EQ("..\\..\\a\\c",1609            remove_dots("..\\..\\a\\b\\..\\c", true, path::Style::windows));1610  EXPECT_EQ("C:\\a\\c", remove_dots("C:\\foo\\bar//..\\..\\a\\c", true,1611                                    path::Style::windows));1612 1613  EXPECT_EQ("C:\\bar",1614            remove_dots("C:/foo/../bar", true, path::Style::windows));1615  EXPECT_EQ("C:\\foo\\bar",1616            remove_dots("C:/foo/bar", true, path::Style::windows));1617  EXPECT_EQ("C:\\foo\\bar",1618            remove_dots("C:/foo\\bar", true, path::Style::windows));1619  EXPECT_EQ("\\", remove_dots("/", true, path::Style::windows));1620  EXPECT_EQ("C:\\", remove_dots("C:/", true, path::Style::windows));1621 1622  // Some clients of remove_dots expect it to remove trailing slashes. Again,1623  // this is emergent behavior that VFS relies on, and not inherently part of1624  // the specification.1625  EXPECT_EQ("C:\\foo\\bar",1626            remove_dots("C:\\foo\\bar\\", true, path::Style::windows));1627  EXPECT_EQ("/foo/bar",1628            remove_dots("/foo/bar/", true, path::Style::posix));1629 1630  // A double separator is rewritten.1631  EXPECT_EQ("C:\\foo\\bar",1632            remove_dots("C:/foo//bar", true, path::Style::windows));1633 1634  SmallString<64> Path1(".\\.\\c");1635  EXPECT_TRUE(path::remove_dots(Path1, true, path::Style::windows));1636  EXPECT_EQ("c", Path1);1637 1638  EXPECT_EQ("foolz/wat",1639            remove_dots("././/foolz/wat", false, path::Style::posix));1640  EXPECT_EQ("", remove_dots("./////", false, path::Style::posix));1641 1642  EXPECT_EQ("a/../b/c", remove_dots("./a/../b/c", false, path::Style::posix));1643  EXPECT_EQ("b/c", remove_dots("./a/../b/c", true, path::Style::posix));1644  EXPECT_EQ("c", remove_dots("././c", true, path::Style::posix));1645  EXPECT_EQ("../a/c", remove_dots("../a/b/../c", true, path::Style::posix));1646  EXPECT_EQ("../../a/c",1647            remove_dots("../../a/b/../c", true, path::Style::posix));1648  EXPECT_EQ("/a/c", remove_dots("/../../a/c", true, path::Style::posix));1649  EXPECT_EQ("/a/c",1650            remove_dots("/../a/b//../././/c", true, path::Style::posix));1651  EXPECT_EQ("/", remove_dots("/", true, path::Style::posix));1652 1653  // FIXME: Leaving behind this double leading slash seems like a bug.1654  EXPECT_EQ("//foo/bar",1655            remove_dots("//foo/bar/", true, path::Style::posix));1656 1657  SmallString<64> Path2("././c");1658  EXPECT_TRUE(path::remove_dots(Path2, true, path::Style::posix));1659  EXPECT_EQ("c", Path2);1660}1661 1662TEST(Support, ReplacePathPrefix) {1663  SmallString<64> Path1("/foo");1664  SmallString<64> Path2("/old/foo");1665  SmallString<64> Path3("/oldnew/foo");1666  SmallString<64> Path4("C:\\old/foo\\bar");1667  SmallString<64> OldPrefix("/old");1668  SmallString<64> OldPrefixSep("/old/");1669  SmallString<64> OldPrefixWin("c:/oLD/F");1670  SmallString<64> NewPrefix("/new");1671  SmallString<64> NewPrefix2("/longernew");1672  SmallString<64> EmptyPrefix("");1673  bool Found;1674 1675  SmallString<64> Path = Path1;1676  Found = path::replace_path_prefix(Path, OldPrefix, NewPrefix);1677  EXPECT_FALSE(Found);1678  EXPECT_EQ(Path, "/foo");1679  Path = Path2;1680  Found = path::replace_path_prefix(Path, OldPrefix, NewPrefix);1681  EXPECT_TRUE(Found);1682  EXPECT_EQ(Path, "/new/foo");1683  Path = Path2;1684  Found = path::replace_path_prefix(Path, OldPrefix, NewPrefix2);1685  EXPECT_TRUE(Found);1686  EXPECT_EQ(Path, "/longernew/foo");1687  Path = Path1;1688  Found = path::replace_path_prefix(Path, EmptyPrefix, NewPrefix);1689  EXPECT_TRUE(Found);1690  EXPECT_EQ(Path, "/new/foo");1691  Path = Path2;1692  Found = path::replace_path_prefix(Path, OldPrefix, EmptyPrefix);1693  EXPECT_TRUE(Found);1694  EXPECT_EQ(Path, "/foo");1695  Path = Path2;1696  Found = path::replace_path_prefix(Path, OldPrefixSep, EmptyPrefix);1697  EXPECT_TRUE(Found);1698  EXPECT_EQ(Path, "foo");1699  Path = Path3;1700  Found = path::replace_path_prefix(Path, OldPrefix, NewPrefix);1701  EXPECT_TRUE(Found);1702  EXPECT_EQ(Path, "/newnew/foo");1703  Path = Path3;1704  Found = path::replace_path_prefix(Path, OldPrefix, NewPrefix2);1705  EXPECT_TRUE(Found);1706  EXPECT_EQ(Path, "/longernewnew/foo");1707  Path = Path1;1708  Found = path::replace_path_prefix(Path, EmptyPrefix, NewPrefix);1709  EXPECT_TRUE(Found);1710  EXPECT_EQ(Path, "/new/foo");1711  Path = OldPrefix;1712  Found = path::replace_path_prefix(Path, OldPrefix, NewPrefix);1713  EXPECT_TRUE(Found);1714  EXPECT_EQ(Path, "/new");1715  Path = OldPrefixSep;1716  Found = path::replace_path_prefix(Path, OldPrefix, NewPrefix);1717  EXPECT_TRUE(Found);1718  EXPECT_EQ(Path, "/new/");1719  Path = OldPrefix;1720  Found = path::replace_path_prefix(Path, OldPrefixSep, NewPrefix);1721  EXPECT_FALSE(Found);1722  EXPECT_EQ(Path, "/old");1723  Path = Path4;1724  Found = path::replace_path_prefix(Path, OldPrefixWin, NewPrefix,1725                                    path::Style::windows);1726  EXPECT_TRUE(Found);1727  EXPECT_EQ(Path, "/newoo\\bar");1728  Path = Path4;1729  Found = path::replace_path_prefix(Path, OldPrefixWin, NewPrefix,1730                                    path::Style::posix);1731  EXPECT_FALSE(Found);1732  EXPECT_EQ(Path, "C:\\old/foo\\bar");1733}1734 1735TEST_F(FileSystemTest, OpenFileForRead) {1736  // Create a temp file.1737  int FileDescriptor;1738  SmallString<64> TempPath;1739  ASSERT_NO_ERROR(1740      fs::createTemporaryFile("prefix", "temp", FileDescriptor, TempPath));1741  FileRemover Cleanup(TempPath);1742 1743  // Make sure it exists.1744  ASSERT_TRUE(sys::fs::exists(Twine(TempPath)));1745 1746  // Open the file for read1747  int FileDescriptor2;1748  SmallString<64> ResultPath;1749  ASSERT_NO_ERROR(fs::openFileForRead(Twine(TempPath), FileDescriptor2,1750                                      fs::OF_None, &ResultPath))1751 1752  // If we succeeded, check that the paths are the same (modulo case):1753  if (!ResultPath.empty()) {1754    // The paths returned by createTemporaryFile and getPathFromOpenFD1755    // should reference the same file on disk.1756    fs::UniqueID D1, D2;1757    ASSERT_NO_ERROR(fs::getUniqueID(Twine(TempPath), D1));1758    ASSERT_NO_ERROR(fs::getUniqueID(Twine(ResultPath), D2));1759    ASSERT_EQ(D1, D2);1760  }1761  ::close(FileDescriptor);1762  ::close(FileDescriptor2);1763 1764#ifdef _WIN321765  // Since Windows Vista, file access time is not updated by default.1766  // This is instead updated manually by openFileForRead.1767  // https://blogs.technet.microsoft.com/filecab/2006/11/07/disabling-last-access-time-in-windows-vista-to-improve-ntfs-performance/1768  // This part of the unit test is Windows specific as the updating of1769  // access times can be disabled on Linux using /etc/fstab.1770 1771  // Set access time to UNIX epoch.1772  ASSERT_NO_ERROR(sys::fs::openFileForWrite(Twine(TempPath), FileDescriptor,1773                                            fs::CD_OpenExisting));1774  TimePoint<> Epoch(std::chrono::milliseconds(0));1775  ASSERT_NO_ERROR(fs::setLastAccessAndModificationTime(FileDescriptor, Epoch));1776  ::close(FileDescriptor);1777 1778  // Open the file and ensure access time is updated, when forced.1779  ASSERT_NO_ERROR(fs::openFileForRead(Twine(TempPath), FileDescriptor,1780                                      fs::OF_UpdateAtime, &ResultPath));1781 1782  sys::fs::file_status Status;1783  ASSERT_NO_ERROR(sys::fs::status(FileDescriptor, Status));1784  auto FileAccessTime = Status.getLastAccessedTime();1785 1786  ASSERT_NE(Epoch, FileAccessTime);1787  ::close(FileDescriptor);1788 1789  // Ideally this test would include a case when ATime is not forced to update,1790  // however the expected behaviour will differ depending on the configuration1791  // of the Windows file system.1792#endif1793}1794 1795TEST_F(FileSystemTest, OpenDirectoryAsFileForRead) {1796  std::string Buf(5, '?');1797  Expected<fs::file_t> FD = fs::openNativeFileForRead(TestDirectory);1798#ifdef _WIN321799  EXPECT_EQ(errorToErrorCode(FD.takeError()), errc::is_a_directory);1800#else1801  ASSERT_THAT_EXPECTED(FD, Succeeded());1802  auto Close = make_scope_exit([&] { fs::closeFile(*FD); });1803  Expected<size_t> BytesRead =1804      fs::readNativeFile(*FD, MutableArrayRef(&*Buf.begin(), Buf.size()));1805  EXPECT_EQ(errorToErrorCode(BytesRead.takeError()), errc::is_a_directory);1806#endif1807}1808 1809TEST_F(FileSystemTest, OpenDirectoryAsFileForWrite) {1810  int FD;1811  std::error_code EC = fs::openFileForWrite(Twine(TestDirectory), FD);1812  if (!EC)1813    ::close(FD);1814  EXPECT_EQ(EC, errc::is_a_directory);1815}1816 1817static void createFileWithData(const Twine &Path, bool ShouldExistBefore,1818                               fs::CreationDisposition Disp, StringRef Data) {1819  int FD;1820  ASSERT_EQ(ShouldExistBefore, fs::exists(Path));1821  ASSERT_NO_ERROR(fs::openFileForWrite(Path, FD, Disp));1822  FileDescriptorCloser Closer(FD);1823  ASSERT_TRUE(fs::exists(Path));1824 1825  ASSERT_EQ(Data.size(), (size_t)write(FD, Data.data(), Data.size()));1826}1827 1828static void verifyFileContents(const Twine &Path, StringRef Contents) {1829  auto Buffer = MemoryBuffer::getFile(Path);1830  ASSERT_TRUE((bool)Buffer);1831  StringRef Data = Buffer.get()->getBuffer();1832  ASSERT_EQ(Data, Contents);1833}1834 1835TEST_F(FileSystemTest, CreateNew) {1836  int FD;1837  std::optional<FileDescriptorCloser> Closer;1838 1839  // Succeeds if the file does not exist.1840  ASSERT_FALSE(fs::exists(NonExistantFile));1841  ASSERT_NO_ERROR(fs::openFileForWrite(NonExistantFile, FD, fs::CD_CreateNew));1842  ASSERT_TRUE(fs::exists(NonExistantFile));1843 1844  FileRemover Cleanup(NonExistantFile);1845  Closer.emplace(FD);1846 1847  // And creates a file of size 0.1848  sys::fs::file_status Status;1849  ASSERT_NO_ERROR(sys::fs::status(FD, Status));1850  EXPECT_EQ(0ULL, Status.getSize());1851 1852  // Close this first, before trying to re-open the file.1853  Closer.reset();1854 1855  // But fails if the file does exist.1856  ASSERT_ERROR(fs::openFileForWrite(NonExistantFile, FD, fs::CD_CreateNew));1857}1858 1859TEST_F(FileSystemTest, CreateAlways) {1860  int FD;1861  std::optional<FileDescriptorCloser> Closer;1862 1863  // Succeeds if the file does not exist.1864  ASSERT_FALSE(fs::exists(NonExistantFile));1865  ASSERT_NO_ERROR(1866      fs::openFileForWrite(NonExistantFile, FD, fs::CD_CreateAlways));1867 1868  Closer.emplace(FD);1869 1870  ASSERT_TRUE(fs::exists(NonExistantFile));1871 1872  FileRemover Cleanup(NonExistantFile);1873 1874  // And creates a file of size 0.1875  uint64_t FileSize;1876  ASSERT_NO_ERROR(sys::fs::file_size(NonExistantFile, FileSize));1877  ASSERT_EQ(0ULL, FileSize);1878 1879  // If we write some data to it re-create it with CreateAlways, it succeeds and1880  // truncates to 0 bytes.1881  ASSERT_EQ(4, write(FD, "Test", 4));1882 1883  Closer.reset();1884 1885  ASSERT_NO_ERROR(sys::fs::file_size(NonExistantFile, FileSize));1886  ASSERT_EQ(4ULL, FileSize);1887 1888  ASSERT_NO_ERROR(1889      fs::openFileForWrite(NonExistantFile, FD, fs::CD_CreateAlways));1890  Closer.emplace(FD);1891  ASSERT_NO_ERROR(sys::fs::file_size(NonExistantFile, FileSize));1892  ASSERT_EQ(0ULL, FileSize);1893}1894 1895TEST_F(FileSystemTest, OpenExisting) {1896  int FD;1897 1898  // Fails if the file does not exist.1899  ASSERT_FALSE(fs::exists(NonExistantFile));1900  ASSERT_ERROR(fs::openFileForWrite(NonExistantFile, FD, fs::CD_OpenExisting));1901  ASSERT_FALSE(fs::exists(NonExistantFile));1902 1903  // Make a dummy file now so that we can try again when the file does exist.1904  createFileWithData(NonExistantFile, false, fs::CD_CreateNew, "Fizz");1905  FileRemover Cleanup(NonExistantFile);1906  uint64_t FileSize;1907  ASSERT_NO_ERROR(sys::fs::file_size(NonExistantFile, FileSize));1908  ASSERT_EQ(4ULL, FileSize);1909 1910  // If we re-create it with different data, it overwrites rather than1911  // appending.1912  createFileWithData(NonExistantFile, true, fs::CD_OpenExisting, "Buzz");1913  verifyFileContents(NonExistantFile, "Buzz");1914}1915 1916TEST_F(FileSystemTest, OpenAlways) {1917  // Succeeds if the file does not exist.1918  createFileWithData(NonExistantFile, false, fs::CD_OpenAlways, "Fizz");1919  FileRemover Cleanup(NonExistantFile);1920  uint64_t FileSize;1921  ASSERT_NO_ERROR(sys::fs::file_size(NonExistantFile, FileSize));1922  ASSERT_EQ(4ULL, FileSize);1923 1924  // Now re-open it and write again, verifying the contents get over-written.1925  createFileWithData(NonExistantFile, true, fs::CD_OpenAlways, "Bu");1926  verifyFileContents(NonExistantFile, "Buzz");1927}1928 1929TEST_F(FileSystemTest, AppendSetsCorrectFileOffset) {1930  fs::CreationDisposition Disps[] = {fs::CD_CreateAlways, fs::CD_OpenAlways,1931                                     fs::CD_OpenExisting};1932 1933  // Write some data and re-open it with every possible disposition (this is a1934  // hack that shouldn't work, but is left for compatibility.  OF_Append1935  // overrides1936  // the specified disposition.1937  for (fs::CreationDisposition Disp : Disps) {1938    int FD;1939    std::optional<FileDescriptorCloser> Closer;1940 1941    createFileWithData(NonExistantFile, false, fs::CD_CreateNew, "Fizz");1942 1943    FileRemover Cleanup(NonExistantFile);1944 1945    uint64_t FileSize;1946    ASSERT_NO_ERROR(sys::fs::file_size(NonExistantFile, FileSize));1947    ASSERT_EQ(4ULL, FileSize);1948    ASSERT_NO_ERROR(1949        fs::openFileForWrite(NonExistantFile, FD, Disp, fs::OF_Append));1950    Closer.emplace(FD);1951    ASSERT_NO_ERROR(sys::fs::file_size(NonExistantFile, FileSize));1952    ASSERT_EQ(4ULL, FileSize);1953 1954    ASSERT_EQ(4, write(FD, "Buzz", 4));1955    Closer.reset();1956 1957    verifyFileContents(NonExistantFile, "FizzBuzz");1958  }1959}1960 1961static void verifyRead(int FD, StringRef Data, bool ShouldSucceed) {1962  std::vector<char> Buffer;1963  Buffer.resize(Data.size());1964  int Result = ::read(FD, Buffer.data(), Buffer.size());1965  if (ShouldSucceed) {1966    ASSERT_EQ((size_t)Result, Data.size());1967    ASSERT_EQ(Data, StringRef(Buffer.data(), Buffer.size()));1968  } else {1969    ASSERT_EQ(-1, Result);1970    ASSERT_EQ(EBADF, errno);1971  }1972}1973 1974static void verifyWrite(int FD, StringRef Data, bool ShouldSucceed) {1975  int Result = ::write(FD, Data.data(), Data.size());1976  if (ShouldSucceed)1977    ASSERT_EQ((size_t)Result, Data.size());1978  else {1979    ASSERT_EQ(-1, Result);1980    ASSERT_EQ(EBADF, errno);1981  }1982}1983 1984TEST_F(FileSystemTest, ReadOnlyFileCantWrite) {1985  createFileWithData(NonExistantFile, false, fs::CD_CreateNew, "Fizz");1986  FileRemover Cleanup(NonExistantFile);1987 1988  int FD;1989  ASSERT_NO_ERROR(fs::openFileForRead(NonExistantFile, FD));1990  FileDescriptorCloser Closer(FD);1991 1992  verifyWrite(FD, "Buzz", false);1993  verifyRead(FD, "Fizz", true);1994}1995 1996TEST_F(FileSystemTest, WriteOnlyFileCantRead) {1997  createFileWithData(NonExistantFile, false, fs::CD_CreateNew, "Fizz");1998  FileRemover Cleanup(NonExistantFile);1999 2000  int FD;2001  ASSERT_NO_ERROR(2002      fs::openFileForWrite(NonExistantFile, FD, fs::CD_OpenExisting));2003  FileDescriptorCloser Closer(FD);2004  verifyRead(FD, "Fizz", false);2005  verifyWrite(FD, "Buzz", true);2006}2007 2008TEST_F(FileSystemTest, ReadWriteFileCanReadOrWrite) {2009  createFileWithData(NonExistantFile, false, fs::CD_CreateNew, "Fizz");2010  FileRemover Cleanup(NonExistantFile);2011 2012  int FD;2013  ASSERT_NO_ERROR(fs::openFileForReadWrite(NonExistantFile, FD,2014                                           fs::CD_OpenExisting, fs::OF_None));2015  FileDescriptorCloser Closer(FD);2016  verifyRead(FD, "Fizz", true);2017  verifyWrite(FD, "Buzz", true);2018}2019 2020TEST_F(FileSystemTest, readNativeFile) {2021  createFileWithData(NonExistantFile, false, fs::CD_CreateNew, "01234");2022  FileRemover Cleanup(NonExistantFile);2023  const auto &Read = [&](size_t ToRead) -> Expected<std::string> {2024    std::string Buf(ToRead, '?');2025    Expected<fs::file_t> FD = fs::openNativeFileForRead(NonExistantFile);2026    if (!FD)2027      return FD.takeError();2028    auto Close = make_scope_exit([&] { fs::closeFile(*FD); });2029    if (Expected<size_t> BytesRead = fs::readNativeFile(2030            *FD, MutableArrayRef(&*Buf.begin(), Buf.size())))2031      return Buf.substr(0, *BytesRead);2032    else2033      return BytesRead.takeError();2034  };2035  EXPECT_THAT_EXPECTED(Read(5), HasValue("01234"));2036  EXPECT_THAT_EXPECTED(Read(3), HasValue("012"));2037  EXPECT_THAT_EXPECTED(Read(6), HasValue("01234"));2038}2039 2040TEST_F(FileSystemTest, readNativeFileToEOF) {2041  constexpr StringLiteral Content = "0123456789";2042  createFileWithData(NonExistantFile, false, fs::CD_CreateNew, Content);2043  FileRemover Cleanup(NonExistantFile);2044  const auto &Read = [&](SmallVectorImpl<char> &V,2045                         std::optional<ssize_t> ChunkSize) {2046    Expected<fs::file_t> FD = fs::openNativeFileForRead(NonExistantFile);2047    if (!FD)2048      return FD.takeError();2049    auto Close = make_scope_exit([&] { fs::closeFile(*FD); });2050    if (ChunkSize)2051      return fs::readNativeFileToEOF(*FD, V, *ChunkSize);2052    return fs::readNativeFileToEOF(*FD, V);2053  };2054 2055  // Check basic operation.2056  {2057    SmallString<0> NoSmall;2058    SmallString<fs::DefaultReadChunkSize + Content.size()> StaysSmall;2059    SmallVectorImpl<char> *Vectors[] = {2060        static_cast<SmallVectorImpl<char> *>(&NoSmall),2061        static_cast<SmallVectorImpl<char> *>(&StaysSmall),2062    };2063    for (SmallVectorImpl<char> *V : Vectors) {2064      ASSERT_THAT_ERROR(Read(*V, std::nullopt), Succeeded());2065      ASSERT_EQ(Content, StringRef(V->begin(), V->size()));2066    }2067    ASSERT_EQ(fs::DefaultReadChunkSize + Content.size(), StaysSmall.capacity());2068 2069    // Check appending.2070    {2071      constexpr StringLiteral Prefix = "prefix-";2072      for (SmallVectorImpl<char> *V : Vectors) {2073        V->assign(Prefix.begin(), Prefix.end());2074        ASSERT_THAT_ERROR(Read(*V, std::nullopt), Succeeded());2075        ASSERT_EQ((Prefix + Content).str(), StringRef(V->begin(), V->size()));2076      }2077    }2078  }2079 2080  // Check that the chunk size (if specified) is respected.2081  SmallString<Content.size() + 5> SmallChunks;2082  ASSERT_THAT_ERROR(Read(SmallChunks, 5), Succeeded());2083  ASSERT_EQ(SmallChunks, Content);2084  ASSERT_EQ(Content.size() + 5, SmallChunks.capacity());2085}2086 2087TEST_F(FileSystemTest, readNativeFileSlice) {2088  createFileWithData(NonExistantFile, false, fs::CD_CreateNew, "01234");2089  FileRemover Cleanup(NonExistantFile);2090  Expected<fs::file_t> FD = fs::openNativeFileForRead(NonExistantFile);2091  ASSERT_THAT_EXPECTED(FD, Succeeded());2092  auto Close = make_scope_exit([&] { fs::closeFile(*FD); });2093  const auto &Read = [&](size_t Offset,2094                         size_t ToRead) -> Expected<std::string> {2095    std::string Buf(ToRead, '?');2096    if (Expected<size_t> BytesRead = fs::readNativeFileSlice(2097            *FD, MutableArrayRef(&*Buf.begin(), Buf.size()), Offset))2098      return Buf.substr(0, *BytesRead);2099    else2100      return BytesRead.takeError();2101  };2102  EXPECT_THAT_EXPECTED(Read(0, 5), HasValue("01234"));2103  EXPECT_THAT_EXPECTED(Read(0, 3), HasValue("012"));2104  EXPECT_THAT_EXPECTED(Read(2, 3), HasValue("234"));2105  EXPECT_THAT_EXPECTED(Read(0, 6), HasValue("01234"));2106  EXPECT_THAT_EXPECTED(Read(2, 6), HasValue("234"));2107  EXPECT_THAT_EXPECTED(Read(5, 5), HasValue(""));2108}2109 2110TEST_F(FileSystemTest, is_local) {2111  bool TestDirectoryIsLocal;2112  ASSERT_NO_ERROR(fs::is_local(TestDirectory, TestDirectoryIsLocal));2113  EXPECT_EQ(TestDirectoryIsLocal, fs::is_local(TestDirectory));2114 2115  int FD;2116  SmallString<128> TempPath;2117  ASSERT_NO_ERROR(2118      fs::createUniqueFile(Twine(TestDirectory) + "/temp", FD, TempPath));2119  FileRemover Cleanup(TempPath);2120 2121  // Make sure it exists.2122  ASSERT_TRUE(sys::fs::exists(Twine(TempPath)));2123 2124  bool TempFileIsLocal;2125  ASSERT_NO_ERROR(fs::is_local(FD, TempFileIsLocal));2126  EXPECT_EQ(TempFileIsLocal, fs::is_local(FD));2127  ::close(FD);2128 2129  // Expect that the file and its parent directory are equally local or equally2130  // remote.2131  EXPECT_EQ(TestDirectoryIsLocal, TempFileIsLocal);2132}2133 2134TEST_F(FileSystemTest, getUmask) {2135#ifdef _WIN322136  EXPECT_EQ(fs::getUmask(), 0U) << "Should always be 0 on Windows.";2137#else2138  unsigned OldMask = ::umask(0022);2139  unsigned CurrentMask = fs::getUmask();2140  EXPECT_EQ(CurrentMask, 0022U)2141      << "getUmask() didn't return previously set umask()";2142  EXPECT_EQ(::umask(OldMask), mode_t(0022U))2143      << "getUmask() may have changed umask()";2144#endif2145}2146 2147TEST_F(FileSystemTest, RespectUmask) {2148#ifndef _WIN322149  unsigned OldMask = ::umask(0022);2150 2151  int FD;2152  SmallString<128> TempPath;2153  ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "temp", FD, TempPath));2154 2155  fs::perms AllRWE = static_cast<fs::perms>(0777);2156 2157  ASSERT_NO_ERROR(fs::setPermissions(TempPath, AllRWE));2158 2159  ErrorOr<fs::perms> Perms = fs::getPermissions(TempPath);2160  ASSERT_TRUE(!!Perms);2161  EXPECT_EQ(Perms.get(), AllRWE) << "Should have ignored umask by default";2162 2163  ASSERT_NO_ERROR(fs::setPermissions(TempPath, AllRWE));2164 2165  Perms = fs::getPermissions(TempPath);2166  ASSERT_TRUE(!!Perms);2167  EXPECT_EQ(Perms.get(), AllRWE) << "Should have ignored umask";2168 2169  ASSERT_NO_ERROR(2170      fs::setPermissions(FD, static_cast<fs::perms>(AllRWE & ~fs::getUmask())));2171  Perms = fs::getPermissions(TempPath);2172  ASSERT_TRUE(!!Perms);2173  EXPECT_EQ(Perms.get(), static_cast<fs::perms>(0755))2174      << "Did not respect umask";2175 2176  (void)::umask(0057);2177 2178  ASSERT_NO_ERROR(2179      fs::setPermissions(FD, static_cast<fs::perms>(AllRWE & ~fs::getUmask())));2180  Perms = fs::getPermissions(TempPath);2181  ASSERT_TRUE(!!Perms);2182  EXPECT_EQ(Perms.get(), static_cast<fs::perms>(0720))2183      << "Did not respect umask";2184 2185  (void)::umask(OldMask);2186  (void)::close(FD);2187#endif2188}2189 2190TEST_F(FileSystemTest, set_current_path) {2191  SmallString<128> path;2192 2193  ASSERT_NO_ERROR(fs::current_path(path));2194  ASSERT_NE(TestDirectory, path);2195 2196  struct RestorePath {2197    SmallString<128> path;2198    RestorePath(const SmallString<128> &path) : path(path) {}2199    ~RestorePath() { fs::set_current_path(path); }2200  } restore_path(path);2201 2202  ASSERT_NO_ERROR(fs::set_current_path(TestDirectory));2203 2204  ASSERT_NO_ERROR(fs::current_path(path));2205 2206  fs::UniqueID D1, D2;2207  ASSERT_NO_ERROR(fs::getUniqueID(TestDirectory, D1));2208  ASSERT_NO_ERROR(fs::getUniqueID(path, D2));2209  ASSERT_EQ(D1, D2) << "D1: " << TestDirectory << "\nD2: " << path;2210}2211 2212TEST_F(FileSystemTest, permissions) {2213  int FD;2214  SmallString<64> TempPath;2215  ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "temp", FD, TempPath));2216  FileRemover Cleanup(TempPath);2217 2218  // Make sure it exists.2219  ASSERT_TRUE(fs::exists(Twine(TempPath)));2220 2221  auto CheckPermissions = [&](fs::perms Expected) {2222    ErrorOr<fs::perms> Actual = fs::getPermissions(TempPath);2223    return Actual && *Actual == Expected;2224  };2225 2226  std::error_code NoError;2227  EXPECT_EQ(fs::setPermissions(TempPath, fs::all_all), NoError);2228  EXPECT_TRUE(CheckPermissions(fs::all_all));2229 2230  EXPECT_EQ(fs::setPermissions(TempPath, fs::all_read | fs::all_exe), NoError);2231  EXPECT_TRUE(CheckPermissions(fs::all_read | fs::all_exe));2232 2233#if defined(_WIN32)2234  fs::perms ReadOnly = fs::all_read | fs::all_exe;2235  EXPECT_EQ(fs::setPermissions(TempPath, fs::no_perms), NoError);2236  EXPECT_TRUE(CheckPermissions(ReadOnly));2237 2238  EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_read), NoError);2239  EXPECT_TRUE(CheckPermissions(ReadOnly));2240 2241  EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_write), NoError);2242  EXPECT_TRUE(CheckPermissions(fs::all_all));2243 2244  EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_exe), NoError);2245  EXPECT_TRUE(CheckPermissions(ReadOnly));2246 2247  EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_all), NoError);2248  EXPECT_TRUE(CheckPermissions(fs::all_all));2249 2250  EXPECT_EQ(fs::setPermissions(TempPath, fs::group_read), NoError);2251  EXPECT_TRUE(CheckPermissions(ReadOnly));2252 2253  EXPECT_EQ(fs::setPermissions(TempPath, fs::group_write), NoError);2254  EXPECT_TRUE(CheckPermissions(fs::all_all));2255 2256  EXPECT_EQ(fs::setPermissions(TempPath, fs::group_exe), NoError);2257  EXPECT_TRUE(CheckPermissions(ReadOnly));2258 2259  EXPECT_EQ(fs::setPermissions(TempPath, fs::group_all), NoError);2260  EXPECT_TRUE(CheckPermissions(fs::all_all));2261 2262  EXPECT_EQ(fs::setPermissions(TempPath, fs::others_read), NoError);2263  EXPECT_TRUE(CheckPermissions(ReadOnly));2264 2265  EXPECT_EQ(fs::setPermissions(TempPath, fs::others_write), NoError);2266  EXPECT_TRUE(CheckPermissions(fs::all_all));2267 2268  EXPECT_EQ(fs::setPermissions(TempPath, fs::others_exe), NoError);2269  EXPECT_TRUE(CheckPermissions(ReadOnly));2270 2271  EXPECT_EQ(fs::setPermissions(TempPath, fs::others_all), NoError);2272  EXPECT_TRUE(CheckPermissions(fs::all_all));2273 2274  EXPECT_EQ(fs::setPermissions(TempPath, fs::all_read), NoError);2275  EXPECT_TRUE(CheckPermissions(ReadOnly));2276 2277  EXPECT_EQ(fs::setPermissions(TempPath, fs::all_write), NoError);2278  EXPECT_TRUE(CheckPermissions(fs::all_all));2279 2280  EXPECT_EQ(fs::setPermissions(TempPath, fs::all_exe), NoError);2281  EXPECT_TRUE(CheckPermissions(ReadOnly));2282 2283  EXPECT_EQ(fs::setPermissions(TempPath, fs::set_uid_on_exe), NoError);2284  EXPECT_TRUE(CheckPermissions(ReadOnly));2285 2286  EXPECT_EQ(fs::setPermissions(TempPath, fs::set_gid_on_exe), NoError);2287  EXPECT_TRUE(CheckPermissions(ReadOnly));2288 2289  EXPECT_EQ(fs::setPermissions(TempPath, fs::sticky_bit), NoError);2290  EXPECT_TRUE(CheckPermissions(ReadOnly));2291 2292  EXPECT_EQ(fs::setPermissions(TempPath, fs::set_uid_on_exe |2293                                             fs::set_gid_on_exe |2294                                             fs::sticky_bit),2295            NoError);2296  EXPECT_TRUE(CheckPermissions(ReadOnly));2297 2298  EXPECT_EQ(fs::setPermissions(TempPath, ReadOnly | fs::set_uid_on_exe |2299                                             fs::set_gid_on_exe |2300                                             fs::sticky_bit),2301            NoError);2302  EXPECT_TRUE(CheckPermissions(ReadOnly));2303 2304  EXPECT_EQ(fs::setPermissions(TempPath, fs::all_perms), NoError);2305  EXPECT_TRUE(CheckPermissions(fs::all_all));2306#else2307  EXPECT_EQ(fs::setPermissions(TempPath, fs::no_perms), NoError);2308  EXPECT_TRUE(CheckPermissions(fs::no_perms));2309 2310  EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_read), NoError);2311  EXPECT_TRUE(CheckPermissions(fs::owner_read));2312 2313  EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_write), NoError);2314  EXPECT_TRUE(CheckPermissions(fs::owner_write));2315 2316  EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_exe), NoError);2317  EXPECT_TRUE(CheckPermissions(fs::owner_exe));2318 2319  EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_all), NoError);2320  EXPECT_TRUE(CheckPermissions(fs::owner_all));2321 2322  EXPECT_EQ(fs::setPermissions(TempPath, fs::group_read), NoError);2323  EXPECT_TRUE(CheckPermissions(fs::group_read));2324 2325  EXPECT_EQ(fs::setPermissions(TempPath, fs::group_write), NoError);2326  EXPECT_TRUE(CheckPermissions(fs::group_write));2327 2328  EXPECT_EQ(fs::setPermissions(TempPath, fs::group_exe), NoError);2329  EXPECT_TRUE(CheckPermissions(fs::group_exe));2330 2331  EXPECT_EQ(fs::setPermissions(TempPath, fs::group_all), NoError);2332  EXPECT_TRUE(CheckPermissions(fs::group_all));2333 2334  EXPECT_EQ(fs::setPermissions(TempPath, fs::others_read), NoError);2335  EXPECT_TRUE(CheckPermissions(fs::others_read));2336 2337  EXPECT_EQ(fs::setPermissions(TempPath, fs::others_write), NoError);2338  EXPECT_TRUE(CheckPermissions(fs::others_write));2339 2340  EXPECT_EQ(fs::setPermissions(TempPath, fs::others_exe), NoError);2341  EXPECT_TRUE(CheckPermissions(fs::others_exe));2342 2343  EXPECT_EQ(fs::setPermissions(TempPath, fs::others_all), NoError);2344  EXPECT_TRUE(CheckPermissions(fs::others_all));2345 2346  EXPECT_EQ(fs::setPermissions(TempPath, fs::all_read), NoError);2347  EXPECT_TRUE(CheckPermissions(fs::all_read));2348 2349  EXPECT_EQ(fs::setPermissions(TempPath, fs::all_write), NoError);2350  EXPECT_TRUE(CheckPermissions(fs::all_write));2351 2352  EXPECT_EQ(fs::setPermissions(TempPath, fs::all_exe), NoError);2353  EXPECT_TRUE(CheckPermissions(fs::all_exe));2354 2355  EXPECT_EQ(fs::setPermissions(TempPath, fs::set_uid_on_exe), NoError);2356  EXPECT_TRUE(CheckPermissions(fs::set_uid_on_exe));2357 2358  EXPECT_EQ(fs::setPermissions(TempPath, fs::set_gid_on_exe), NoError);2359  EXPECT_TRUE(CheckPermissions(fs::set_gid_on_exe));2360 2361  // Modern BSDs require root to set the sticky bit on files.2362  // AIX and Solaris without root will mask off (i.e., lose) the sticky bit2363  // on files.2364#if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) &&  \2365    !defined(_AIX) && !(defined(__sun__) && defined(__svr4__))2366  EXPECT_EQ(fs::setPermissions(TempPath, fs::sticky_bit), NoError);2367  EXPECT_TRUE(CheckPermissions(fs::sticky_bit));2368 2369  EXPECT_EQ(fs::setPermissions(TempPath, fs::set_uid_on_exe |2370                                             fs::set_gid_on_exe |2371                                             fs::sticky_bit),2372            NoError);2373  EXPECT_TRUE(CheckPermissions(fs::set_uid_on_exe | fs::set_gid_on_exe |2374                               fs::sticky_bit));2375 2376  EXPECT_EQ(fs::setPermissions(TempPath, fs::all_read | fs::set_uid_on_exe |2377                                             fs::set_gid_on_exe |2378                                             fs::sticky_bit),2379            NoError);2380  EXPECT_TRUE(CheckPermissions(fs::all_read | fs::set_uid_on_exe |2381                               fs::set_gid_on_exe | fs::sticky_bit));2382 2383  EXPECT_EQ(fs::setPermissions(TempPath, fs::all_perms), NoError);2384  EXPECT_TRUE(CheckPermissions(fs::all_perms));2385#endif // !FreeBSD && !NetBSD && !OpenBSD && !AIX2386 2387  EXPECT_EQ(fs::setPermissions(TempPath, fs::all_perms & ~fs::sticky_bit),2388                               NoError);2389  EXPECT_TRUE(CheckPermissions(fs::all_perms & ~fs::sticky_bit));2390#endif2391}2392 2393#ifdef _WIN322394TEST_F(FileSystemTest, widenPath) {2395  const std::wstring LongPathPrefix(L"\\\\?\\");2396 2397  // Test that the length limit is checked against the UTF-16 length and not the2398  // UTF-8 length.2399  std::string Input("C:\\foldername\\");2400  const std::string Pi("\xcf\x80"); // UTF-8 lower case pi.2401  // Add Pi up to the MAX_PATH limit.2402  const size_t NumChars = MAX_PATH - Input.size() - 1;2403  for (size_t i = 0; i < NumChars; ++i)2404    Input += Pi;2405  // Check that UTF-8 length already exceeds MAX_PATH.2406  EXPECT_GT(Input.size(), (size_t)MAX_PATH);2407  SmallVector<wchar_t, MAX_PATH + 16> Result;2408  ASSERT_NO_ERROR(windows::widenPath(Input, Result));2409  // Result should not start with the long path prefix.2410  EXPECT_TRUE(std::wmemcmp(Result.data(), LongPathPrefix.c_str(),2411                           LongPathPrefix.size()) != 0);2412  EXPECT_EQ(Result.size(), (size_t)MAX_PATH - 1);2413 2414  // Add another Pi to exceed the MAX_PATH limit.2415  Input += Pi;2416  // Construct the expected result.2417  SmallVector<wchar_t, MAX_PATH + 16> Expected;2418  ASSERT_NO_ERROR(windows::UTF8ToUTF16(Input, Expected));2419  Expected.insert(Expected.begin(), LongPathPrefix.begin(),2420                  LongPathPrefix.end());2421 2422  ASSERT_NO_ERROR(windows::widenPath(Input, Result));2423  EXPECT_EQ(Result, Expected);2424  // Pass a path with forward slashes, check that it ends up with2425  // backslashes when widened with the long path prefix.2426  SmallString<MAX_PATH + 16> InputForward(Input);2427  path::make_preferred(InputForward, path::Style::windows_slash);2428  ASSERT_NO_ERROR(windows::widenPath(InputForward, Result));2429  EXPECT_EQ(Result, Expected);2430 2431  // Pass a path which has the long path prefix prepended originally, but2432  // which is short enough to not require the long path prefix. If such a2433  // path is passed with forward slashes, make sure it gets normalized to2434  // backslashes.2435  SmallString<MAX_PATH + 16> PrefixedPath("\\\\?\\C:\\foldername");2436  ASSERT_NO_ERROR(windows::UTF8ToUTF16(PrefixedPath, Expected));2437  // Mangle the input to forward slashes.2438  path::make_preferred(PrefixedPath, path::Style::windows_slash);2439  ASSERT_NO_ERROR(windows::widenPath(PrefixedPath, Result));2440  EXPECT_EQ(Result, Expected);2441 2442  // A short path with an inconsistent prefix is passed through as-is; this2443  // is a degenerate case that we currently don't care about handling.2444  PrefixedPath.assign("/\\?/C:/foldername");2445  ASSERT_NO_ERROR(windows::UTF8ToUTF16(PrefixedPath, Expected));2446  ASSERT_NO_ERROR(windows::widenPath(PrefixedPath, Result));2447  EXPECT_EQ(Result, Expected);2448 2449  // Test that UNC paths are handled correctly.2450  const std::string ShareName("\\\\sharename\\");2451  const std::string FileName("\\filename");2452  // Initialize directory name so that the input is within the MAX_PATH limit.2453  const char DirChar = 'x';2454  std::string DirName(MAX_PATH - ShareName.size() - FileName.size() - 1,2455                      DirChar);2456 2457  Input = ShareName + DirName + FileName;2458  ASSERT_NO_ERROR(windows::widenPath(Input, Result));2459  // Result should not start with the long path prefix.2460  EXPECT_TRUE(std::wmemcmp(Result.data(), LongPathPrefix.c_str(),2461                           LongPathPrefix.size()) != 0);2462  EXPECT_EQ(Result.size(), (size_t)MAX_PATH - 1);2463 2464  // Extend the directory name so the input exceeds the MAX_PATH limit.2465  DirName += DirChar;2466  Input = ShareName + DirName + FileName;2467  // Construct the expected result.2468  ASSERT_NO_ERROR(windows::UTF8ToUTF16(StringRef(Input).substr(2), Expected));2469  const std::wstring UNCPrefix(LongPathPrefix + L"UNC\\");2470  Expected.insert(Expected.begin(), UNCPrefix.begin(), UNCPrefix.end());2471 2472  ASSERT_NO_ERROR(windows::widenPath(Input, Result));2473  EXPECT_EQ(Result, Expected);2474 2475  // Check that Unix separators are handled correctly.2476  llvm::replace(Input, '\\', '/');2477  ASSERT_NO_ERROR(windows::widenPath(Input, Result));2478  EXPECT_EQ(Result, Expected);2479 2480  // Check the removal of "dots".2481  Input = ShareName + DirName + "\\.\\foo\\.\\.." + FileName;2482  ASSERT_NO_ERROR(windows::widenPath(Input, Result));2483  EXPECT_EQ(Result, Expected);2484}2485#endif2486 2487#ifdef _WIN322488// Windows refuses lock request if file region is already locked by the same2489// process. POSIX system in this case updates the existing lock.2490TEST_F(FileSystemTest, FileLocker) {2491  using namespace std::chrono;2492  int FD;2493  std::error_code EC;2494  SmallString<64> TempPath;2495  EC = fs::createTemporaryFile("test", "temp", FD, TempPath);2496  ASSERT_NO_ERROR(EC);2497  FileRemover Cleanup(TempPath);2498  raw_fd_ostream Stream(TempPath, EC);2499 2500  EC = fs::tryLockFile(FD);2501  ASSERT_NO_ERROR(EC);2502  EC = fs::unlockFile(FD);2503  ASSERT_NO_ERROR(EC);2504 2505  if (auto L = Stream.lock()) {2506    ASSERT_ERROR(fs::tryLockFile(FD));2507    ASSERT_NO_ERROR(L->unlock());2508    ASSERT_NO_ERROR(fs::tryLockFile(FD));2509    ASSERT_NO_ERROR(fs::unlockFile(FD));2510  } else {2511    ADD_FAILURE();2512    handleAllErrors(L.takeError(), [&](ErrorInfoBase &EIB) {});2513  }2514 2515  ASSERT_NO_ERROR(fs::tryLockFile(FD));2516  ASSERT_NO_ERROR(fs::unlockFile(FD));2517 2518  {2519    Expected<fs::FileLocker> L1 = Stream.lock();2520    ASSERT_THAT_EXPECTED(L1, Succeeded());2521    raw_fd_ostream Stream2(FD, false);2522    Expected<fs::FileLocker> L2 = Stream2.tryLockFor(250ms);2523    ASSERT_THAT_EXPECTED(L2, Failed());2524    ASSERT_NO_ERROR(L1->unlock());2525    Expected<fs::FileLocker> L3 = Stream.tryLockFor(0ms);2526    ASSERT_THAT_EXPECTED(L3, Succeeded());2527  }2528 2529  ASSERT_NO_ERROR(fs::tryLockFile(FD));2530  ASSERT_NO_ERROR(fs::unlockFile(FD));2531}2532#endif2533 2534TEST_F(FileSystemTest, CopyFile) {2535  unittest::TempDir RootTestDirectory("CopyFileTest", /*Unique=*/true);2536 2537  SmallVector<std::string> Data;2538  SmallVector<SmallString<128>> Sources;2539  for (int I = 0, E = 3; I != E; ++I) {2540    Data.push_back(Twine(I).str());2541    Sources.emplace_back(RootTestDirectory.path());2542    path::append(Sources.back(), "source" + Data.back() + ".txt");2543    createFileWithData(Sources.back(), /*ShouldExistBefore=*/false,2544                       fs::CD_CreateNew, Data.back());2545  }2546 2547  // Copy the first file to a non-existing file.2548  SmallString<128> Destination(RootTestDirectory.path());2549  path::append(Destination, "destination");2550  ASSERT_FALSE(fs::exists(Destination));2551  fs::copy_file(Sources[0], Destination);2552  verifyFileContents(Destination, Data[0]);2553 2554  // Copy the second file to an existing file.2555  fs::copy_file(Sources[1], Destination);2556  verifyFileContents(Destination, Data[1]);2557 2558  // Note: The remaining logic is targeted at a potential failure case related2559  // to file cloning and symlinks on Darwin. On Windows, fs::create_link() does2560  // not return success here so the test is skipped.2561#if !defined(_WIN32)2562  // Set up a symlink to the third file.2563  SmallString<128> Symlink(RootTestDirectory.path());2564  path::append(Symlink, "symlink");2565  ASSERT_NO_ERROR(fs::create_link(path::filename(Sources[2]), Symlink));2566  verifyFileContents(Symlink, Data[2]);2567 2568  // fs::getUniqueID() should follow symlinks. Otherwise, this isn't good test2569  // coverage.2570  fs::UniqueID SymlinkID;2571  fs::UniqueID Data2ID;2572  ASSERT_NO_ERROR(fs::getUniqueID(Symlink, SymlinkID));2573  ASSERT_NO_ERROR(fs::getUniqueID(Sources[2], Data2ID));2574  ASSERT_EQ(SymlinkID, Data2ID);2575 2576  // Copy the third file through the symlink.2577  fs::copy_file(Symlink, Destination);2578  verifyFileContents(Destination, Data[2]);2579 2580  // Confirm the destination is not a link to the original file, and not a2581  // symlink.2582  bool IsDestinationSymlink;2583  ASSERT_NO_ERROR(fs::is_symlink_file(Destination, IsDestinationSymlink));2584  ASSERT_FALSE(IsDestinationSymlink);2585  fs::UniqueID DestinationID;2586  ASSERT_NO_ERROR(fs::getUniqueID(Destination, DestinationID));2587  ASSERT_NE(SymlinkID, DestinationID);2588#endif2589}2590 2591} // anonymous namespace2592