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-exception
6 //
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/ADT/Triple.h"
14 #include "llvm/BinaryFormat/Magic.h"
15 #include "llvm/Config/llvm-config.h"
16 #include "llvm/Support/Compiler.h"
17 #include "llvm/Support/ConvertUTF.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/Host.h"
23 #include "llvm/Support/MemoryBuffer.h"
24 #include "llvm/Support/raw_ostream.h"
25 #include "llvm/Testing/Support/Error.h"
26 #include "gmock/gmock.h"
27 #include "gtest/gtest.h"
28
29 #ifdef _WIN32
30 #include "llvm/ADT/ArrayRef.h"
31 #include "llvm/Support/Chrono.h"
32 #include "llvm/Support/Windows/WindowsSupport.h"
33 #include <windows.h>
34 #include <winerror.h>
35 #endif
36
37 #ifdef LLVM_ON_UNIX
38 #include <pwd.h>
39 #include <sys/stat.h>
40 #endif
41
42 using namespace llvm;
43 using namespace llvm::sys;
44
45 #define ASSERT_NO_ERROR(x) \
46 if (std::error_code ASSERT_NO_ERROR_ec = x) { \
47 SmallString<128> MessageStorage; \
48 raw_svector_ostream Message(MessageStorage); \
49 Message << #x ": did not return errc::success.\n" \
50 << "error number: " << ASSERT_NO_ERROR_ec.value() << "\n" \
51 << "error message: " << ASSERT_NO_ERROR_ec.message() << "\n"; \
52 GTEST_FATAL_FAILURE_(MessageStorage.c_str()); \
53 } else { \
54 }
55
56 #define EXPECT_NO_ERROR(x) \
57 if (std::error_code EXPECT_NO_ERROR_ec = x) { \
58 SmallString<128> MessageStorage; \
59 raw_svector_ostream Message(MessageStorage); \
60 Message << #x ": did not return errc::success.\n" \
61 << "error number: " << EXPECT_NO_ERROR_ec.value() << "\n" \
62 << "error message: " << EXPECT_NO_ERROR_ec.message() << "\n"; \
63 GTEST_NONFATAL_FAILURE_(MessageStorage.c_str()); \
64 } else { \
65 }
66
67 #define ASSERT_ERROR(x) \
68 if (!x) { \
69 SmallString<128> MessageStorage; \
70 raw_svector_ostream Message(MessageStorage); \
71 Message << #x ": did not return a failure error code.\n"; \
72 GTEST_FATAL_FAILURE_(MessageStorage.c_str()); \
73 }
74
75 namespace {
76
77 struct FileDescriptorCloser {
FileDescriptorCloser__anon7bfe64730111::FileDescriptorCloser78 explicit FileDescriptorCloser(int FD) : FD(FD) {}
~FileDescriptorCloser__anon7bfe64730111::FileDescriptorCloser79 ~FileDescriptorCloser() { ::close(FD); }
80 int FD;
81 };
82
TEST(is_separator,Works)83 TEST(is_separator, Works) {
84 EXPECT_TRUE(path::is_separator('/'));
85 EXPECT_FALSE(path::is_separator('\0'));
86 EXPECT_FALSE(path::is_separator('-'));
87 EXPECT_FALSE(path::is_separator(' '));
88
89 EXPECT_TRUE(path::is_separator('\\', path::Style::windows));
90 EXPECT_FALSE(path::is_separator('\\', path::Style::posix));
91
92 #ifdef _WIN32
93 EXPECT_TRUE(path::is_separator('\\'));
94 #else
95 EXPECT_FALSE(path::is_separator('\\'));
96 #endif
97 }
98
TEST(Support,Path)99 TEST(Support, Path) {
100 SmallVector<StringRef, 40> paths;
101 paths.push_back("");
102 paths.push_back(".");
103 paths.push_back("..");
104 paths.push_back("foo");
105 paths.push_back("/");
106 paths.push_back("/foo");
107 paths.push_back("foo/");
108 paths.push_back("/foo/");
109 paths.push_back("foo/bar");
110 paths.push_back("/foo/bar");
111 paths.push_back("//net");
112 paths.push_back("//net/");
113 paths.push_back("//net/foo");
114 paths.push_back("///foo///");
115 paths.push_back("///foo///bar");
116 paths.push_back("/.");
117 paths.push_back("./");
118 paths.push_back("/..");
119 paths.push_back("../");
120 paths.push_back("foo/.");
121 paths.push_back("foo/..");
122 paths.push_back("foo/./");
123 paths.push_back("foo/./bar");
124 paths.push_back("foo/..");
125 paths.push_back("foo/../");
126 paths.push_back("foo/../bar");
127 paths.push_back("c:");
128 paths.push_back("c:/");
129 paths.push_back("c:foo");
130 paths.push_back("c:/foo");
131 paths.push_back("c:foo/");
132 paths.push_back("c:/foo/");
133 paths.push_back("c:/foo/bar");
134 paths.push_back("prn:");
135 paths.push_back("c:\\");
136 paths.push_back("c:foo");
137 paths.push_back("c:\\foo");
138 paths.push_back("c:foo\\");
139 paths.push_back("c:\\foo\\");
140 paths.push_back("c:\\foo/");
141 paths.push_back("c:/foo\\bar");
142
143 for (SmallVector<StringRef, 40>::const_iterator i = paths.begin(),
144 e = paths.end();
145 i != e;
146 ++i) {
147 SCOPED_TRACE(*i);
148 SmallVector<StringRef, 5> ComponentStack;
149 for (sys::path::const_iterator ci = sys::path::begin(*i),
150 ce = sys::path::end(*i);
151 ci != ce;
152 ++ci) {
153 EXPECT_FALSE(ci->empty());
154 ComponentStack.push_back(*ci);
155 }
156
157 SmallVector<StringRef, 5> ReverseComponentStack;
158 for (sys::path::reverse_iterator ci = sys::path::rbegin(*i),
159 ce = sys::path::rend(*i);
160 ci != ce;
161 ++ci) {
162 EXPECT_FALSE(ci->empty());
163 ReverseComponentStack.push_back(*ci);
164 }
165 std::reverse(ReverseComponentStack.begin(), ReverseComponentStack.end());
166 EXPECT_THAT(ComponentStack, testing::ContainerEq(ReverseComponentStack));
167
168 // Crash test most of the API - since we're iterating over all of our paths
169 // here there isn't really anything reasonable to assert on in the results.
170 (void)path::has_root_path(*i);
171 (void)path::root_path(*i);
172 (void)path::has_root_name(*i);
173 (void)path::root_name(*i);
174 (void)path::has_root_directory(*i);
175 (void)path::root_directory(*i);
176 (void)path::has_parent_path(*i);
177 (void)path::parent_path(*i);
178 (void)path::has_filename(*i);
179 (void)path::filename(*i);
180 (void)path::has_stem(*i);
181 (void)path::stem(*i);
182 (void)path::has_extension(*i);
183 (void)path::extension(*i);
184 (void)path::is_absolute(*i);
185 (void)path::is_relative(*i);
186
187 SmallString<128> temp_store;
188 temp_store = *i;
189 ASSERT_NO_ERROR(fs::make_absolute(temp_store));
190 temp_store = *i;
191 path::remove_filename(temp_store);
192
193 temp_store = *i;
194 path::replace_extension(temp_store, "ext");
195 StringRef filename(temp_store.begin(), temp_store.size()), stem, ext;
196 stem = path::stem(filename);
197 ext = path::extension(filename);
198 EXPECT_EQ(*sys::path::rbegin(filename), (stem + ext).str());
199
200 path::native(*i, temp_store);
201 }
202
203 {
204 SmallString<32> Relative("foo.cpp");
205 sys::fs::make_absolute("/root", Relative);
206 Relative[5] = '/'; // Fix up windows paths.
207 ASSERT_EQ("/root/foo.cpp", Relative);
208 }
209
210 {
211 SmallString<32> Relative("foo.cpp");
212 sys::fs::make_absolute("//root", Relative);
213 Relative[6] = '/'; // Fix up windows paths.
214 ASSERT_EQ("//root/foo.cpp", Relative);
215 }
216 }
217
TEST(Support,PathRoot)218 TEST(Support, PathRoot) {
219 ASSERT_EQ(path::root_name("//net/hello", path::Style::posix).str(), "//net");
220 ASSERT_EQ(path::root_name("c:/hello", path::Style::posix).str(), "");
221 ASSERT_EQ(path::root_name("c:/hello", path::Style::windows).str(), "c:");
222 ASSERT_EQ(path::root_name("/hello", path::Style::posix).str(), "");
223
224 ASSERT_EQ(path::root_directory("/goo/hello", path::Style::posix).str(), "/");
225 ASSERT_EQ(path::root_directory("c:/hello", path::Style::windows).str(), "/");
226 ASSERT_EQ(path::root_directory("d/file.txt", path::Style::posix).str(), "");
227 ASSERT_EQ(path::root_directory("d/file.txt", path::Style::windows).str(), "");
228
229 SmallVector<StringRef, 40> paths;
230 paths.push_back("");
231 paths.push_back(".");
232 paths.push_back("..");
233 paths.push_back("foo");
234 paths.push_back("/");
235 paths.push_back("/foo");
236 paths.push_back("foo/");
237 paths.push_back("/foo/");
238 paths.push_back("foo/bar");
239 paths.push_back("/foo/bar");
240 paths.push_back("//net");
241 paths.push_back("//net/");
242 paths.push_back("//net/foo");
243 paths.push_back("///foo///");
244 paths.push_back("///foo///bar");
245 paths.push_back("/.");
246 paths.push_back("./");
247 paths.push_back("/..");
248 paths.push_back("../");
249 paths.push_back("foo/.");
250 paths.push_back("foo/..");
251 paths.push_back("foo/./");
252 paths.push_back("foo/./bar");
253 paths.push_back("foo/..");
254 paths.push_back("foo/../");
255 paths.push_back("foo/../bar");
256 paths.push_back("c:");
257 paths.push_back("c:/");
258 paths.push_back("c:foo");
259 paths.push_back("c:/foo");
260 paths.push_back("c:foo/");
261 paths.push_back("c:/foo/");
262 paths.push_back("c:/foo/bar");
263 paths.push_back("prn:");
264 paths.push_back("c:\\");
265 paths.push_back("c:foo");
266 paths.push_back("c:\\foo");
267 paths.push_back("c:foo\\");
268 paths.push_back("c:\\foo\\");
269 paths.push_back("c:\\foo/");
270 paths.push_back("c:/foo\\bar");
271
272 for (StringRef p : paths) {
273 ASSERT_EQ(
274 path::root_name(p, path::Style::posix).str() + path::root_directory(p, path::Style::posix).str(),
275 path::root_path(p, path::Style::posix).str());
276
277 ASSERT_EQ(
278 path::root_name(p, path::Style::windows).str() + path::root_directory(p, path::Style::windows).str(),
279 path::root_path(p, path::Style::windows).str());
280 }
281 }
282
TEST(Support,FilenameParent)283 TEST(Support, FilenameParent) {
284 EXPECT_EQ("/", path::filename("/"));
285 EXPECT_EQ("", path::parent_path("/"));
286
287 EXPECT_EQ("\\", path::filename("c:\\", path::Style::windows));
288 EXPECT_EQ("c:", path::parent_path("c:\\", path::Style::windows));
289
290 EXPECT_EQ("/", path::filename("///"));
291 EXPECT_EQ("", path::parent_path("///"));
292
293 EXPECT_EQ("\\", path::filename("c:\\\\", path::Style::windows));
294 EXPECT_EQ("c:", path::parent_path("c:\\\\", path::Style::windows));
295
296 EXPECT_EQ("bar", path::filename("/foo/bar"));
297 EXPECT_EQ("/foo", path::parent_path("/foo/bar"));
298
299 EXPECT_EQ("foo", path::filename("/foo"));
300 EXPECT_EQ("/", path::parent_path("/foo"));
301
302 EXPECT_EQ("foo", path::filename("foo"));
303 EXPECT_EQ("", path::parent_path("foo"));
304
305 EXPECT_EQ(".", path::filename("foo/"));
306 EXPECT_EQ("foo", path::parent_path("foo/"));
307
308 EXPECT_EQ("//net", path::filename("//net"));
309 EXPECT_EQ("", path::parent_path("//net"));
310
311 EXPECT_EQ("/", path::filename("//net/"));
312 EXPECT_EQ("//net", path::parent_path("//net/"));
313
314 EXPECT_EQ("foo", path::filename("//net/foo"));
315 EXPECT_EQ("//net/", path::parent_path("//net/foo"));
316
317 // These checks are just to make sure we do something reasonable with the
318 // paths below. They are not meant to prescribe the one true interpretation of
319 // these paths. Other decompositions (e.g. "//" -> "" + "//") are also
320 // possible.
321 EXPECT_EQ("/", path::filename("//"));
322 EXPECT_EQ("", path::parent_path("//"));
323
324 EXPECT_EQ("\\", path::filename("\\\\", path::Style::windows));
325 EXPECT_EQ("", path::parent_path("\\\\", path::Style::windows));
326
327 EXPECT_EQ("\\", path::filename("\\\\\\", path::Style::windows));
328 EXPECT_EQ("", path::parent_path("\\\\\\", path::Style::windows));
329 }
330
331 static std::vector<StringRef>
GetComponents(StringRef Path,path::Style S=path::Style::native)332 GetComponents(StringRef Path, path::Style S = path::Style::native) {
333 return {path::begin(Path, S), path::end(Path)};
334 }
335
TEST(Support,PathIterator)336 TEST(Support, PathIterator) {
337 EXPECT_THAT(GetComponents("/foo"), testing::ElementsAre("/", "foo"));
338 EXPECT_THAT(GetComponents("/"), testing::ElementsAre("/"));
339 EXPECT_THAT(GetComponents("//"), testing::ElementsAre("/"));
340 EXPECT_THAT(GetComponents("///"), testing::ElementsAre("/"));
341 EXPECT_THAT(GetComponents("c/d/e/foo.txt"),
342 testing::ElementsAre("c", "d", "e", "foo.txt"));
343 EXPECT_THAT(GetComponents(".c/.d/../."),
344 testing::ElementsAre(".c", ".d", "..", "."));
345 EXPECT_THAT(GetComponents("/c/d/e/foo.txt"),
346 testing::ElementsAre("/", "c", "d", "e", "foo.txt"));
347 EXPECT_THAT(GetComponents("/.c/.d/../."),
348 testing::ElementsAre("/", ".c", ".d", "..", "."));
349 EXPECT_THAT(GetComponents("c:\\c\\e\\foo.txt", path::Style::windows),
350 testing::ElementsAre("c:", "\\", "c", "e", "foo.txt"));
351 EXPECT_THAT(GetComponents("//net/"), testing::ElementsAre("//net", "/"));
352 EXPECT_THAT(GetComponents("//net/c/foo.txt"),
353 testing::ElementsAre("//net", "/", "c", "foo.txt"));
354 }
355
TEST(Support,AbsolutePathIteratorEnd)356 TEST(Support, AbsolutePathIteratorEnd) {
357 // Trailing slashes are converted to '.' unless they are part of the root path.
358 SmallVector<std::pair<StringRef, path::Style>, 4> Paths;
359 Paths.emplace_back("/foo/", path::Style::native);
360 Paths.emplace_back("/foo//", path::Style::native);
361 Paths.emplace_back("//net/foo/", path::Style::native);
362 Paths.emplace_back("c:\\foo\\", path::Style::windows);
363
364 for (auto &Path : Paths) {
365 SCOPED_TRACE(Path.first);
366 StringRef LastComponent = *path::rbegin(Path.first, Path.second);
367 EXPECT_EQ(".", LastComponent);
368 }
369
370 SmallVector<std::pair<StringRef, path::Style>, 3> RootPaths;
371 RootPaths.emplace_back("/", path::Style::native);
372 RootPaths.emplace_back("//net/", path::Style::native);
373 RootPaths.emplace_back("c:\\", path::Style::windows);
374 RootPaths.emplace_back("//net//", path::Style::native);
375 RootPaths.emplace_back("c:\\\\", path::Style::windows);
376
377 for (auto &Path : RootPaths) {
378 SCOPED_TRACE(Path.first);
379 StringRef LastComponent = *path::rbegin(Path.first, Path.second);
380 EXPECT_EQ(1u, LastComponent.size());
381 EXPECT_TRUE(path::is_separator(LastComponent[0], Path.second));
382 }
383 }
384
385 #ifdef _WIN32
getEnvWin(const wchar_t * Var)386 std::string getEnvWin(const wchar_t *Var) {
387 std::string expected;
388 if (wchar_t const *path = ::_wgetenv(Var)) {
389 auto pathLen = ::wcslen(path);
390 ArrayRef<char> ref{reinterpret_cast<char const *>(path),
391 pathLen * sizeof(wchar_t)};
392 convertUTF16ToUTF8String(ref, expected);
393 }
394 return expected;
395 }
396 #else
397 // RAII helper to set and restore an environment variable.
398 class WithEnv {
399 const char *Var;
400 llvm::Optional<std::string> OriginalValue;
401
402 public:
WithEnv(const char * Var,const char * Value)403 WithEnv(const char *Var, const char *Value) : Var(Var) {
404 if (const char *V = ::getenv(Var))
405 OriginalValue.emplace(V);
406 if (Value)
407 ::setenv(Var, Value, 1);
408 else
409 ::unsetenv(Var);
410 }
~WithEnv()411 ~WithEnv() {
412 if (OriginalValue)
413 ::setenv(Var, OriginalValue->c_str(), 1);
414 else
415 ::unsetenv(Var);
416 }
417 };
418 #endif
419
TEST(Support,HomeDirectory)420 TEST(Support, HomeDirectory) {
421 std::string expected;
422 #ifdef _WIN32
423 expected = getEnvWin(L"USERPROFILE");
424 #else
425 if (char const *path = ::getenv("HOME"))
426 expected = path;
427 #endif
428 // Do not try to test it if we don't know what to expect.
429 // On Windows we use something better than env vars.
430 if (!expected.empty()) {
431 SmallString<128> HomeDir;
432 auto status = path::home_directory(HomeDir);
433 EXPECT_TRUE(status);
434 EXPECT_EQ(expected, HomeDir);
435 }
436 }
437
438 // Apple has their own solution for this.
439 #if defined(LLVM_ON_UNIX) && !defined(__APPLE__)
TEST(Support,HomeDirectoryWithNoEnv)440 TEST(Support, HomeDirectoryWithNoEnv) {
441 WithEnv Env("HOME", nullptr);
442
443 // Don't run the test if we have nothing to compare against.
444 struct passwd *pw = getpwuid(getuid());
445 if (!pw || !pw->pw_dir) return;
446 std::string PwDir = pw->pw_dir;
447
448 SmallString<128> HomeDir;
449 EXPECT_TRUE(path::home_directory(HomeDir));
450 EXPECT_EQ(PwDir, HomeDir);
451 }
452
TEST(Support,ConfigDirectoryWithEnv)453 TEST(Support, ConfigDirectoryWithEnv) {
454 WithEnv Env("XDG_CONFIG_HOME", "/xdg/config");
455
456 SmallString<128> ConfigDir;
457 EXPECT_TRUE(path::user_config_directory(ConfigDir));
458 EXPECT_EQ("/xdg/config", ConfigDir);
459 }
460
TEST(Support,ConfigDirectoryNoEnv)461 TEST(Support, ConfigDirectoryNoEnv) {
462 WithEnv Env("XDG_CONFIG_HOME", nullptr);
463
464 SmallString<128> Fallback;
465 ASSERT_TRUE(path::home_directory(Fallback));
466 path::append(Fallback, ".config");
467
468 SmallString<128> CacheDir;
469 EXPECT_TRUE(path::user_config_directory(CacheDir));
470 EXPECT_EQ(Fallback, CacheDir);
471 }
472
TEST(Support,CacheDirectoryWithEnv)473 TEST(Support, CacheDirectoryWithEnv) {
474 WithEnv Env("XDG_CACHE_HOME", "/xdg/cache");
475
476 SmallString<128> CacheDir;
477 EXPECT_TRUE(path::cache_directory(CacheDir));
478 EXPECT_EQ("/xdg/cache", CacheDir);
479 }
480
TEST(Support,CacheDirectoryNoEnv)481 TEST(Support, CacheDirectoryNoEnv) {
482 WithEnv Env("XDG_CACHE_HOME", nullptr);
483
484 SmallString<128> Fallback;
485 ASSERT_TRUE(path::home_directory(Fallback));
486 path::append(Fallback, ".cache");
487
488 SmallString<128> CacheDir;
489 EXPECT_TRUE(path::cache_directory(CacheDir));
490 EXPECT_EQ(Fallback, CacheDir);
491 }
492 #endif
493
494 #ifdef __APPLE__
TEST(Support,ConfigDirectory)495 TEST(Support, ConfigDirectory) {
496 SmallString<128> Fallback;
497 ASSERT_TRUE(path::home_directory(Fallback));
498 path::append(Fallback, "Library/Preferences");
499
500 SmallString<128> ConfigDir;
501 EXPECT_TRUE(path::user_config_directory(ConfigDir));
502 EXPECT_EQ(Fallback, ConfigDir);
503 }
504 #endif
505
506 #ifdef _WIN32
TEST(Support,ConfigDirectory)507 TEST(Support, ConfigDirectory) {
508 std::string Expected = getEnvWin(L"LOCALAPPDATA");
509 // Do not try to test it if we don't know what to expect.
510 if (!Expected.empty()) {
511 SmallString<128> CacheDir;
512 EXPECT_TRUE(path::user_config_directory(CacheDir));
513 EXPECT_EQ(Expected, CacheDir);
514 }
515 }
516
TEST(Support,CacheDirectory)517 TEST(Support, CacheDirectory) {
518 std::string Expected = getEnvWin(L"LOCALAPPDATA");
519 // Do not try to test it if we don't know what to expect.
520 if (!Expected.empty()) {
521 SmallString<128> CacheDir;
522 EXPECT_TRUE(path::cache_directory(CacheDir));
523 EXPECT_EQ(Expected, CacheDir);
524 }
525 }
526 #endif
527
TEST(Support,TempDirectory)528 TEST(Support, TempDirectory) {
529 SmallString<32> TempDir;
530 path::system_temp_directory(false, TempDir);
531 EXPECT_TRUE(!TempDir.empty());
532 TempDir.clear();
533 path::system_temp_directory(true, TempDir);
534 EXPECT_TRUE(!TempDir.empty());
535 }
536
537 #ifdef _WIN32
path2regex(std::string Path)538 static std::string path2regex(std::string Path) {
539 size_t Pos = 0;
540 while ((Pos = Path.find('\\', Pos)) != std::string::npos) {
541 Path.replace(Pos, 1, "\\\\");
542 Pos += 2;
543 }
544 return Path;
545 }
546
547 /// Helper for running temp dir test in separated process. See below.
548 #define EXPECT_TEMP_DIR(prepare, expected) \
549 EXPECT_EXIT( \
550 { \
551 prepare; \
552 SmallString<300> TempDir; \
553 path::system_temp_directory(true, TempDir); \
554 raw_os_ostream(std::cerr) << TempDir; \
555 std::exit(0); \
556 }, \
557 ::testing::ExitedWithCode(0), path2regex(expected))
558
TEST(SupportDeathTest,TempDirectoryOnWindows)559 TEST(SupportDeathTest, TempDirectoryOnWindows) {
560 // In this test we want to check how system_temp_directory responds to
561 // different values of specific env vars. To prevent corrupting env vars of
562 // the current process all checks are done in separated processes.
563 EXPECT_TEMP_DIR(_wputenv_s(L"TMP", L"C:\\OtherFolder"), "C:\\OtherFolder");
564 EXPECT_TEMP_DIR(_wputenv_s(L"TMP", L"C:/Unix/Path/Seperators"),
565 "C:\\Unix\\Path\\Seperators");
566 EXPECT_TEMP_DIR(_wputenv_s(L"TMP", L"Local Path"), ".+\\Local Path$");
567 EXPECT_TEMP_DIR(_wputenv_s(L"TMP", L"F:\\TrailingSep\\"), "F:\\TrailingSep");
568 EXPECT_TEMP_DIR(
569 _wputenv_s(L"TMP", L"C:\\2\x03C0r-\x00B5\x00B3\\\x2135\x2080"),
570 "C:\\2\xCF\x80r-\xC2\xB5\xC2\xB3\\\xE2\x84\xB5\xE2\x82\x80");
571
572 // Test $TMP empty, $TEMP set.
573 EXPECT_TEMP_DIR(
574 {
575 _wputenv_s(L"TMP", L"");
576 _wputenv_s(L"TEMP", L"C:\\Valid\\Path");
577 },
578 "C:\\Valid\\Path");
579
580 // All related env vars empty
581 EXPECT_TEMP_DIR(
582 {
583 _wputenv_s(L"TMP", L"");
584 _wputenv_s(L"TEMP", L"");
585 _wputenv_s(L"USERPROFILE", L"");
586 },
587 "C:\\Temp");
588
589 // Test evn var / path with 260 chars.
590 SmallString<270> Expected{"C:\\Temp\\AB\\123456789"};
591 while (Expected.size() < 260)
592 Expected.append("\\DirNameWith19Charss");
593 ASSERT_EQ(260U, Expected.size());
594 EXPECT_TEMP_DIR(_putenv_s("TMP", Expected.c_str()), Expected.c_str());
595 }
596 #endif
597
598 class FileSystemTest : public testing::Test {
599 protected:
600 /// Unique temporary directory in which all created filesystem entities must
601 /// be placed. It is removed at the end of each test (must be empty).
602 SmallString<128> TestDirectory;
603 SmallString<128> NonExistantFile;
604
SetUp()605 void SetUp() override {
606 ASSERT_NO_ERROR(
607 fs::createUniqueDirectory("file-system-test", TestDirectory));
608 // We don't care about this specific file.
609 errs() << "Test Directory: " << TestDirectory << '\n';
610 errs().flush();
611 NonExistantFile = TestDirectory;
612
613 // Even though this value is hardcoded, is a 128-bit GUID, so we should be
614 // guaranteed that this file will never exist.
615 sys::path::append(NonExistantFile, "1B28B495C16344CB9822E588CD4C3EF0");
616 }
617
TearDown()618 void TearDown() override { ASSERT_NO_ERROR(fs::remove(TestDirectory.str())); }
619 };
620
TEST_F(FileSystemTest,Unique)621 TEST_F(FileSystemTest, Unique) {
622 // Create a temp file.
623 int FileDescriptor;
624 SmallString<64> TempPath;
625 ASSERT_NO_ERROR(
626 fs::createTemporaryFile("prefix", "temp", FileDescriptor, TempPath));
627
628 // The same file should return an identical unique id.
629 fs::UniqueID F1, F2;
630 ASSERT_NO_ERROR(fs::getUniqueID(Twine(TempPath), F1));
631 ASSERT_NO_ERROR(fs::getUniqueID(Twine(TempPath), F2));
632 ASSERT_EQ(F1, F2);
633
634 // Different files should return different unique ids.
635 int FileDescriptor2;
636 SmallString<64> TempPath2;
637 ASSERT_NO_ERROR(
638 fs::createTemporaryFile("prefix", "temp", FileDescriptor2, TempPath2));
639
640 fs::UniqueID D;
641 ASSERT_NO_ERROR(fs::getUniqueID(Twine(TempPath2), D));
642 ASSERT_NE(D, F1);
643 ::close(FileDescriptor2);
644
645 ASSERT_NO_ERROR(fs::remove(Twine(TempPath2)));
646
647 // Two paths representing the same file on disk should still provide the
648 // same unique id. We can test this by making a hard link.
649 ASSERT_NO_ERROR(fs::create_link(Twine(TempPath), Twine(TempPath2)));
650 fs::UniqueID D2;
651 ASSERT_NO_ERROR(fs::getUniqueID(Twine(TempPath2), D2));
652 ASSERT_EQ(D2, F1);
653
654 ::close(FileDescriptor);
655
656 SmallString<128> Dir1;
657 ASSERT_NO_ERROR(
658 fs::createUniqueDirectory("dir1", Dir1));
659 ASSERT_NO_ERROR(fs::getUniqueID(Dir1.c_str(), F1));
660 ASSERT_NO_ERROR(fs::getUniqueID(Dir1.c_str(), F2));
661 ASSERT_EQ(F1, F2);
662
663 SmallString<128> Dir2;
664 ASSERT_NO_ERROR(
665 fs::createUniqueDirectory("dir2", Dir2));
666 ASSERT_NO_ERROR(fs::getUniqueID(Dir2.c_str(), F2));
667 ASSERT_NE(F1, F2);
668 ASSERT_NO_ERROR(fs::remove(Dir1));
669 ASSERT_NO_ERROR(fs::remove(Dir2));
670 ASSERT_NO_ERROR(fs::remove(TempPath2));
671 ASSERT_NO_ERROR(fs::remove(TempPath));
672 }
673
TEST_F(FileSystemTest,RealPath)674 TEST_F(FileSystemTest, RealPath) {
675 ASSERT_NO_ERROR(
676 fs::create_directories(Twine(TestDirectory) + "/test1/test2/test3"));
677 ASSERT_TRUE(fs::exists(Twine(TestDirectory) + "/test1/test2/test3"));
678
679 SmallString<64> RealBase;
680 SmallString<64> Expected;
681 SmallString<64> Actual;
682
683 // TestDirectory itself might be under a symlink or have been specified with
684 // a different case than the existing temp directory. In such cases real_path
685 // on the concatenated path will differ in the TestDirectory portion from
686 // how we specified it. Make sure to compare against the real_path of the
687 // TestDirectory, and not just the value of TestDirectory.
688 ASSERT_NO_ERROR(fs::real_path(TestDirectory, RealBase));
689 path::native(Twine(RealBase) + "/test1/test2", Expected);
690
691 ASSERT_NO_ERROR(fs::real_path(
692 Twine(TestDirectory) + "/././test1/../test1/test2/./test3/..", Actual));
693
694 EXPECT_EQ(Expected, Actual);
695
696 SmallString<64> HomeDir;
697
698 // This can fail if $HOME is not set and getpwuid fails.
699 bool Result = llvm::sys::path::home_directory(HomeDir);
700 if (Result) {
701 ASSERT_NO_ERROR(fs::real_path(HomeDir, Expected));
702 ASSERT_NO_ERROR(fs::real_path("~", Actual, true));
703 EXPECT_EQ(Expected, Actual);
704 ASSERT_NO_ERROR(fs::real_path("~/", Actual, true));
705 EXPECT_EQ(Expected, Actual);
706 }
707
708 ASSERT_NO_ERROR(fs::remove_directories(Twine(TestDirectory) + "/test1"));
709 }
710
TEST_F(FileSystemTest,ExpandTilde)711 TEST_F(FileSystemTest, ExpandTilde) {
712 SmallString<64> Expected;
713 SmallString<64> Actual;
714 SmallString<64> HomeDir;
715
716 // This can fail if $HOME is not set and getpwuid fails.
717 bool Result = llvm::sys::path::home_directory(HomeDir);
718 if (Result) {
719 fs::expand_tilde(HomeDir, Expected);
720
721 fs::expand_tilde("~", Actual);
722 EXPECT_EQ(Expected, Actual);
723
724 #ifdef _WIN32
725 Expected += "\\foo";
726 fs::expand_tilde("~\\foo", Actual);
727 #else
728 Expected += "/foo";
729 fs::expand_tilde("~/foo", Actual);
730 #endif
731
732 EXPECT_EQ(Expected, Actual);
733 }
734 }
735
736 #ifdef LLVM_ON_UNIX
TEST_F(FileSystemTest,RealPathNoReadPerm)737 TEST_F(FileSystemTest, RealPathNoReadPerm) {
738 SmallString<64> Expanded;
739
740 ASSERT_NO_ERROR(
741 fs::create_directories(Twine(TestDirectory) + "/noreadperm"));
742 ASSERT_TRUE(fs::exists(Twine(TestDirectory) + "/noreadperm"));
743
744 fs::setPermissions(Twine(TestDirectory) + "/noreadperm", fs::no_perms);
745 fs::setPermissions(Twine(TestDirectory) + "/noreadperm", fs::all_exe);
746
747 ASSERT_NO_ERROR(fs::real_path(Twine(TestDirectory) + "/noreadperm", Expanded,
748 false));
749
750 ASSERT_NO_ERROR(fs::remove_directories(Twine(TestDirectory) + "/noreadperm"));
751 }
752 #endif
753
754
TEST_F(FileSystemTest,TempFileKeepDiscard)755 TEST_F(FileSystemTest, TempFileKeepDiscard) {
756 // We can keep then discard.
757 auto TempFileOrError = fs::TempFile::create(TestDirectory + "/test-%%%%");
758 ASSERT_TRUE((bool)TempFileOrError);
759 fs::TempFile File = std::move(*TempFileOrError);
760 ASSERT_EQ(-1, TempFileOrError->FD);
761 ASSERT_FALSE((bool)File.keep(TestDirectory + "/keep"));
762 ASSERT_FALSE((bool)File.discard());
763 ASSERT_TRUE(fs::exists(TestDirectory + "/keep"));
764 ASSERT_NO_ERROR(fs::remove(TestDirectory + "/keep"));
765 }
766
TEST_F(FileSystemTest,TempFileDiscardDiscard)767 TEST_F(FileSystemTest, TempFileDiscardDiscard) {
768 // We can discard twice.
769 auto TempFileOrError = fs::TempFile::create(TestDirectory + "/test-%%%%");
770 ASSERT_TRUE((bool)TempFileOrError);
771 fs::TempFile File = std::move(*TempFileOrError);
772 ASSERT_EQ(-1, TempFileOrError->FD);
773 ASSERT_FALSE((bool)File.discard());
774 ASSERT_FALSE((bool)File.discard());
775 ASSERT_FALSE(fs::exists(TestDirectory + "/keep"));
776 }
777
TEST_F(FileSystemTest,TempFiles)778 TEST_F(FileSystemTest, TempFiles) {
779 // Create a temp file.
780 int FileDescriptor;
781 SmallString<64> TempPath;
782 ASSERT_NO_ERROR(
783 fs::createTemporaryFile("prefix", "temp", FileDescriptor, TempPath));
784
785 // Make sure it exists.
786 ASSERT_TRUE(sys::fs::exists(Twine(TempPath)));
787
788 // Create another temp tile.
789 int FD2;
790 SmallString<64> TempPath2;
791 ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "temp", FD2, TempPath2));
792 ASSERT_TRUE(TempPath2.endswith(".temp"));
793 ASSERT_NE(TempPath.str(), TempPath2.str());
794
795 fs::file_status A, B;
796 ASSERT_NO_ERROR(fs::status(Twine(TempPath), A));
797 ASSERT_NO_ERROR(fs::status(Twine(TempPath2), B));
798 EXPECT_FALSE(fs::equivalent(A, B));
799
800 ::close(FD2);
801
802 // Remove Temp2.
803 ASSERT_NO_ERROR(fs::remove(Twine(TempPath2)));
804 ASSERT_NO_ERROR(fs::remove(Twine(TempPath2)));
805 ASSERT_EQ(fs::remove(Twine(TempPath2), false),
806 errc::no_such_file_or_directory);
807
808 std::error_code EC = fs::status(TempPath2.c_str(), B);
809 EXPECT_EQ(EC, errc::no_such_file_or_directory);
810 EXPECT_EQ(B.type(), fs::file_type::file_not_found);
811
812 // Make sure Temp2 doesn't exist.
813 ASSERT_EQ(fs::access(Twine(TempPath2), sys::fs::AccessMode::Exist),
814 errc::no_such_file_or_directory);
815
816 SmallString<64> TempPath3;
817 ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "", TempPath3));
818 ASSERT_FALSE(TempPath3.endswith("."));
819 FileRemover Cleanup3(TempPath3);
820
821 // Create a hard link to Temp1.
822 ASSERT_NO_ERROR(fs::create_link(Twine(TempPath), Twine(TempPath2)));
823 bool equal;
824 ASSERT_NO_ERROR(fs::equivalent(Twine(TempPath), Twine(TempPath2), equal));
825 EXPECT_TRUE(equal);
826 ASSERT_NO_ERROR(fs::status(Twine(TempPath), A));
827 ASSERT_NO_ERROR(fs::status(Twine(TempPath2), B));
828 EXPECT_TRUE(fs::equivalent(A, B));
829
830 // Remove Temp1.
831 ::close(FileDescriptor);
832 ASSERT_NO_ERROR(fs::remove(Twine(TempPath)));
833
834 // Remove the hard link.
835 ASSERT_NO_ERROR(fs::remove(Twine(TempPath2)));
836
837 // Make sure Temp1 doesn't exist.
838 ASSERT_EQ(fs::access(Twine(TempPath), sys::fs::AccessMode::Exist),
839 errc::no_such_file_or_directory);
840
841 #ifdef _WIN32
842 // Path name > 260 chars should get an error.
843 const char *Path270 =
844 "abcdefghijklmnopqrstuvwxyz9abcdefghijklmnopqrstuvwxyz8"
845 "abcdefghijklmnopqrstuvwxyz7abcdefghijklmnopqrstuvwxyz6"
846 "abcdefghijklmnopqrstuvwxyz5abcdefghijklmnopqrstuvwxyz4"
847 "abcdefghijklmnopqrstuvwxyz3abcdefghijklmnopqrstuvwxyz2"
848 "abcdefghijklmnopqrstuvwxyz1abcdefghijklmnopqrstuvwxyz0";
849 EXPECT_EQ(fs::createUniqueFile(Path270, FileDescriptor, TempPath),
850 errc::invalid_argument);
851 // Relative path < 247 chars, no problem.
852 const char *Path216 =
853 "abcdefghijklmnopqrstuvwxyz7abcdefghijklmnopqrstuvwxyz6"
854 "abcdefghijklmnopqrstuvwxyz5abcdefghijklmnopqrstuvwxyz4"
855 "abcdefghijklmnopqrstuvwxyz3abcdefghijklmnopqrstuvwxyz2"
856 "abcdefghijklmnopqrstuvwxyz1abcdefghijklmnopqrstuvwxyz0";
857 ASSERT_NO_ERROR(fs::createTemporaryFile(Path216, "", TempPath));
858 ASSERT_NO_ERROR(fs::remove(Twine(TempPath)));
859 #endif
860 }
861
TEST_F(FileSystemTest,TempFileCollisions)862 TEST_F(FileSystemTest, TempFileCollisions) {
863 SmallString<128> TestDirectory;
864 ASSERT_NO_ERROR(
865 fs::createUniqueDirectory("CreateUniqueFileTest", TestDirectory));
866 FileRemover Cleanup(TestDirectory);
867 SmallString<128> Model = TestDirectory;
868 path::append(Model, "%.tmp");
869 SmallString<128> Path;
870 std::vector<fs::TempFile> TempFiles;
871
872 auto TryCreateTempFile = [&]() {
873 Expected<fs::TempFile> T = fs::TempFile::create(Model);
874 if (T) {
875 TempFiles.push_back(std::move(*T));
876 return true;
877 } else {
878 logAllUnhandledErrors(T.takeError(), errs(),
879 "Failed to create temporary file: ");
880 return false;
881 }
882 };
883
884 // Our single-character template allows for 16 unique names. Check that
885 // calling TryCreateTempFile repeatedly results in 16 successes.
886 // Because the test depends on random numbers, it could theoretically fail.
887 // However, the probability of this happening is tiny: with 32 calls, each
888 // of which will retry up to 128 times, to not get a given digit we would
889 // have to fail at least 15 + 17 * 128 = 2191 attempts. The probability of
890 // 2191 attempts not producing a given hexadecimal digit is
891 // (1 - 1/16) ** 2191 or 3.88e-62.
892 int Successes = 0;
893 for (int i = 0; i < 32; ++i)
894 if (TryCreateTempFile()) ++Successes;
895 EXPECT_EQ(Successes, 16);
896
897 for (fs::TempFile &T : TempFiles)
898 cantFail(T.discard());
899 }
900
TEST_F(FileSystemTest,CreateDir)901 TEST_F(FileSystemTest, CreateDir) {
902 ASSERT_NO_ERROR(fs::create_directory(Twine(TestDirectory) + "foo"));
903 ASSERT_NO_ERROR(fs::create_directory(Twine(TestDirectory) + "foo"));
904 ASSERT_EQ(fs::create_directory(Twine(TestDirectory) + "foo", false),
905 errc::file_exists);
906 ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "foo"));
907
908 #ifdef LLVM_ON_UNIX
909 // Set a 0000 umask so that we can test our directory permissions.
910 mode_t OldUmask = ::umask(0000);
911
912 fs::file_status Status;
913 ASSERT_NO_ERROR(
914 fs::create_directory(Twine(TestDirectory) + "baz500", false,
915 fs::perms::owner_read | fs::perms::owner_exe));
916 ASSERT_NO_ERROR(fs::status(Twine(TestDirectory) + "baz500", Status));
917 ASSERT_EQ(Status.permissions() & fs::perms::all_all,
918 fs::perms::owner_read | fs::perms::owner_exe);
919 ASSERT_NO_ERROR(fs::create_directory(Twine(TestDirectory) + "baz777", false,
920 fs::perms::all_all));
921 ASSERT_NO_ERROR(fs::status(Twine(TestDirectory) + "baz777", Status));
922 ASSERT_EQ(Status.permissions() & fs::perms::all_all, fs::perms::all_all);
923
924 // Restore umask to be safe.
925 ::umask(OldUmask);
926 #endif
927
928 #ifdef _WIN32
929 // Prove that create_directories() can handle a pathname > 248 characters,
930 // which is the documented limit for CreateDirectory().
931 // (248 is MAX_PATH subtracting room for an 8.3 filename.)
932 // Generate a directory path guaranteed to fall into that range.
933 size_t TmpLen = TestDirectory.size();
934 const char *OneDir = "\\123456789";
935 size_t OneDirLen = strlen(OneDir);
936 ASSERT_LT(OneDirLen, 12U);
937 size_t NLevels = ((248 - TmpLen) / OneDirLen) + 1;
938 SmallString<260> LongDir(TestDirectory);
939 for (size_t I = 0; I < NLevels; ++I)
940 LongDir.append(OneDir);
941 ASSERT_NO_ERROR(fs::create_directories(Twine(LongDir)));
942 ASSERT_NO_ERROR(fs::create_directories(Twine(LongDir)));
943 ASSERT_EQ(fs::create_directories(Twine(LongDir), false),
944 errc::file_exists);
945 // Tidy up, "recursively" removing the directories.
946 StringRef ThisDir(LongDir);
947 for (size_t J = 0; J < NLevels; ++J) {
948 ASSERT_NO_ERROR(fs::remove(ThisDir));
949 ThisDir = path::parent_path(ThisDir);
950 }
951
952 // Also verify that paths with Unix separators are handled correctly.
953 std::string LongPathWithUnixSeparators(TestDirectory.str());
954 // Add at least one subdirectory to TestDirectory, and replace slashes with
955 // backslashes
956 do {
957 LongPathWithUnixSeparators.append("/DirNameWith19Charss");
958 } while (LongPathWithUnixSeparators.size() < 260);
959 std::replace(LongPathWithUnixSeparators.begin(),
960 LongPathWithUnixSeparators.end(),
961 '\\', '/');
962 ASSERT_NO_ERROR(fs::create_directories(Twine(LongPathWithUnixSeparators)));
963 // cleanup
964 ASSERT_NO_ERROR(fs::remove_directories(Twine(TestDirectory) +
965 "/DirNameWith19Charss"));
966
967 // Similarly for a relative pathname. Need to set the current directory to
968 // TestDirectory so that the one we create ends up in the right place.
969 char PreviousDir[260];
970 size_t PreviousDirLen = ::GetCurrentDirectoryA(260, PreviousDir);
971 ASSERT_GT(PreviousDirLen, 0U);
972 ASSERT_LT(PreviousDirLen, 260U);
973 ASSERT_NE(::SetCurrentDirectoryA(TestDirectory.c_str()), 0);
974 LongDir.clear();
975 // Generate a relative directory name with absolute length > 248.
976 size_t LongDirLen = 249 - TestDirectory.size();
977 LongDir.assign(LongDirLen, 'a');
978 ASSERT_NO_ERROR(fs::create_directory(Twine(LongDir)));
979 // While we're here, prove that .. and . handling works in these long paths.
980 const char *DotDotDirs = "\\..\\.\\b";
981 LongDir.append(DotDotDirs);
982 ASSERT_NO_ERROR(fs::create_directory("b"));
983 ASSERT_EQ(fs::create_directory(Twine(LongDir), false), errc::file_exists);
984 // And clean up.
985 ASSERT_NO_ERROR(fs::remove("b"));
986 ASSERT_NO_ERROR(fs::remove(
987 Twine(LongDir.substr(0, LongDir.size() - strlen(DotDotDirs)))));
988 ASSERT_NE(::SetCurrentDirectoryA(PreviousDir), 0);
989 #endif
990 }
991
TEST_F(FileSystemTest,DirectoryIteration)992 TEST_F(FileSystemTest, DirectoryIteration) {
993 std::error_code ec;
994 for (fs::directory_iterator i(".", ec), e; i != e; i.increment(ec))
995 ASSERT_NO_ERROR(ec);
996
997 // Create a known hierarchy to recurse over.
998 ASSERT_NO_ERROR(
999 fs::create_directories(Twine(TestDirectory) + "/recursive/a0/aa1"));
1000 ASSERT_NO_ERROR(
1001 fs::create_directories(Twine(TestDirectory) + "/recursive/a0/ab1"));
1002 ASSERT_NO_ERROR(fs::create_directories(Twine(TestDirectory) +
1003 "/recursive/dontlookhere/da1"));
1004 ASSERT_NO_ERROR(
1005 fs::create_directories(Twine(TestDirectory) + "/recursive/z0/za1"));
1006 ASSERT_NO_ERROR(
1007 fs::create_directories(Twine(TestDirectory) + "/recursive/pop/p1"));
1008 typedef std::vector<std::string> v_t;
1009 v_t visited;
1010 for (fs::recursive_directory_iterator i(Twine(TestDirectory)
1011 + "/recursive", ec), e; i != e; i.increment(ec)){
1012 ASSERT_NO_ERROR(ec);
1013 if (path::filename(i->path()) == "p1") {
1014 i.pop();
1015 // FIXME: recursive_directory_iterator should be more robust.
1016 if (i == e) break;
1017 }
1018 if (path::filename(i->path()) == "dontlookhere")
1019 i.no_push();
1020 visited.push_back(std::string(path::filename(i->path())));
1021 }
1022 v_t::const_iterator a0 = find(visited, "a0");
1023 v_t::const_iterator aa1 = find(visited, "aa1");
1024 v_t::const_iterator ab1 = find(visited, "ab1");
1025 v_t::const_iterator dontlookhere = find(visited, "dontlookhere");
1026 v_t::const_iterator da1 = find(visited, "da1");
1027 v_t::const_iterator z0 = find(visited, "z0");
1028 v_t::const_iterator za1 = find(visited, "za1");
1029 v_t::const_iterator pop = find(visited, "pop");
1030 v_t::const_iterator p1 = find(visited, "p1");
1031
1032 // Make sure that each path was visited correctly.
1033 ASSERT_NE(a0, visited.end());
1034 ASSERT_NE(aa1, visited.end());
1035 ASSERT_NE(ab1, visited.end());
1036 ASSERT_NE(dontlookhere, visited.end());
1037 ASSERT_EQ(da1, visited.end()); // Not visited.
1038 ASSERT_NE(z0, visited.end());
1039 ASSERT_NE(za1, visited.end());
1040 ASSERT_NE(pop, visited.end());
1041 ASSERT_EQ(p1, visited.end()); // Not visited.
1042
1043 // Make sure that parents were visited before children. No other ordering
1044 // guarantees can be made across siblings.
1045 ASSERT_LT(a0, aa1);
1046 ASSERT_LT(a0, ab1);
1047 ASSERT_LT(z0, za1);
1048
1049 ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/a0/aa1"));
1050 ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/a0/ab1"));
1051 ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/a0"));
1052 ASSERT_NO_ERROR(
1053 fs::remove(Twine(TestDirectory) + "/recursive/dontlookhere/da1"));
1054 ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/dontlookhere"));
1055 ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/pop/p1"));
1056 ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/pop"));
1057 ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/z0/za1"));
1058 ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/z0"));
1059 ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive"));
1060
1061 // Test recursive_directory_iterator level()
1062 ASSERT_NO_ERROR(
1063 fs::create_directories(Twine(TestDirectory) + "/reclevel/a/b/c"));
1064 fs::recursive_directory_iterator I(Twine(TestDirectory) + "/reclevel", ec), E;
1065 for (int l = 0; I != E; I.increment(ec), ++l) {
1066 ASSERT_NO_ERROR(ec);
1067 EXPECT_EQ(I.level(), l);
1068 }
1069 EXPECT_EQ(I, E);
1070 ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/reclevel/a/b/c"));
1071 ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/reclevel/a/b"));
1072 ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/reclevel/a"));
1073 ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/reclevel"));
1074 }
1075
1076 #ifdef LLVM_ON_UNIX
TEST_F(FileSystemTest,BrokenSymlinkDirectoryIteration)1077 TEST_F(FileSystemTest, BrokenSymlinkDirectoryIteration) {
1078 // Create a known hierarchy to recurse over.
1079 ASSERT_NO_ERROR(fs::create_directories(Twine(TestDirectory) + "/symlink"));
1080 ASSERT_NO_ERROR(
1081 fs::create_link("no_such_file", Twine(TestDirectory) + "/symlink/a"));
1082 ASSERT_NO_ERROR(
1083 fs::create_directories(Twine(TestDirectory) + "/symlink/b/bb"));
1084 ASSERT_NO_ERROR(
1085 fs::create_link("no_such_file", Twine(TestDirectory) + "/symlink/b/ba"));
1086 ASSERT_NO_ERROR(
1087 fs::create_link("no_such_file", Twine(TestDirectory) + "/symlink/b/bc"));
1088 ASSERT_NO_ERROR(
1089 fs::create_link("no_such_file", Twine(TestDirectory) + "/symlink/c"));
1090 ASSERT_NO_ERROR(
1091 fs::create_directories(Twine(TestDirectory) + "/symlink/d/dd/ddd"));
1092 ASSERT_NO_ERROR(fs::create_link(Twine(TestDirectory) + "/symlink/d/dd",
1093 Twine(TestDirectory) + "/symlink/d/da"));
1094 ASSERT_NO_ERROR(
1095 fs::create_link("no_such_file", Twine(TestDirectory) + "/symlink/e"));
1096
1097 typedef std::vector<std::string> v_t;
1098 v_t VisitedNonBrokenSymlinks;
1099 v_t VisitedBrokenSymlinks;
1100 std::error_code ec;
1101 using testing::UnorderedElementsAre;
1102 using testing::UnorderedElementsAreArray;
1103
1104 // Broken symbol links are expected to throw an error.
1105 for (fs::directory_iterator i(Twine(TestDirectory) + "/symlink", ec), e;
1106 i != e; i.increment(ec)) {
1107 ASSERT_NO_ERROR(ec);
1108 if (i->status().getError() ==
1109 std::make_error_code(std::errc::no_such_file_or_directory)) {
1110 VisitedBrokenSymlinks.push_back(std::string(path::filename(i->path())));
1111 continue;
1112 }
1113 VisitedNonBrokenSymlinks.push_back(std::string(path::filename(i->path())));
1114 }
1115 EXPECT_THAT(VisitedNonBrokenSymlinks, UnorderedElementsAre("b", "d"));
1116 VisitedNonBrokenSymlinks.clear();
1117
1118 EXPECT_THAT(VisitedBrokenSymlinks, UnorderedElementsAre("a", "c", "e"));
1119 VisitedBrokenSymlinks.clear();
1120
1121 // Broken symbol links are expected to throw an error.
1122 for (fs::recursive_directory_iterator i(
1123 Twine(TestDirectory) + "/symlink", ec), e; i != e; i.increment(ec)) {
1124 ASSERT_NO_ERROR(ec);
1125 if (i->status().getError() ==
1126 std::make_error_code(std::errc::no_such_file_or_directory)) {
1127 VisitedBrokenSymlinks.push_back(std::string(path::filename(i->path())));
1128 continue;
1129 }
1130 VisitedNonBrokenSymlinks.push_back(std::string(path::filename(i->path())));
1131 }
1132 EXPECT_THAT(VisitedNonBrokenSymlinks,
1133 UnorderedElementsAre("b", "bb", "d", "da", "dd", "ddd", "ddd"));
1134 VisitedNonBrokenSymlinks.clear();
1135
1136 EXPECT_THAT(VisitedBrokenSymlinks,
1137 UnorderedElementsAre("a", "ba", "bc", "c", "e"));
1138 VisitedBrokenSymlinks.clear();
1139
1140 for (fs::recursive_directory_iterator i(
1141 Twine(TestDirectory) + "/symlink", ec, /*follow_symlinks=*/false), e;
1142 i != e; i.increment(ec)) {
1143 ASSERT_NO_ERROR(ec);
1144 if (i->status().getError() ==
1145 std::make_error_code(std::errc::no_such_file_or_directory)) {
1146 VisitedBrokenSymlinks.push_back(std::string(path::filename(i->path())));
1147 continue;
1148 }
1149 VisitedNonBrokenSymlinks.push_back(std::string(path::filename(i->path())));
1150 }
1151 EXPECT_THAT(VisitedNonBrokenSymlinks,
1152 UnorderedElementsAreArray({"a", "b", "ba", "bb", "bc", "c", "d",
1153 "da", "dd", "ddd", "e"}));
1154 VisitedNonBrokenSymlinks.clear();
1155
1156 EXPECT_THAT(VisitedBrokenSymlinks, UnorderedElementsAre());
1157 VisitedBrokenSymlinks.clear();
1158
1159 ASSERT_NO_ERROR(fs::remove_directories(Twine(TestDirectory) + "/symlink"));
1160 }
1161 #endif
1162
1163 #ifdef _WIN32
TEST_F(FileSystemTest,UTF8ToUTF16DirectoryIteration)1164 TEST_F(FileSystemTest, UTF8ToUTF16DirectoryIteration) {
1165 // The Windows filesystem support uses UTF-16 and converts paths from the
1166 // input UTF-8. The UTF-16 equivalent of the input path can be shorter in
1167 // length.
1168
1169 // This test relies on TestDirectory not being so long such that MAX_PATH
1170 // would be exceeded (see widenPath). If that were the case, the UTF-16
1171 // path is likely to be longer than the input.
1172 const char *Pi = "\xcf\x80"; // UTF-8 lower case pi.
1173 std::string RootDir = (TestDirectory + "/" + Pi).str();
1174
1175 // Create test directories.
1176 ASSERT_NO_ERROR(fs::create_directories(Twine(RootDir) + "/a"));
1177 ASSERT_NO_ERROR(fs::create_directories(Twine(RootDir) + "/b"));
1178
1179 std::error_code EC;
1180 unsigned Count = 0;
1181 for (fs::directory_iterator I(Twine(RootDir), EC), E; I != E;
1182 I.increment(EC)) {
1183 ASSERT_NO_ERROR(EC);
1184 StringRef DirName = path::filename(I->path());
1185 EXPECT_TRUE(DirName == "a" || DirName == "b");
1186 ++Count;
1187 }
1188 EXPECT_EQ(Count, 2U);
1189
1190 ASSERT_NO_ERROR(fs::remove(Twine(RootDir) + "/a"));
1191 ASSERT_NO_ERROR(fs::remove(Twine(RootDir) + "/b"));
1192 ASSERT_NO_ERROR(fs::remove(Twine(RootDir)));
1193 }
1194 #endif
1195
TEST_F(FileSystemTest,Remove)1196 TEST_F(FileSystemTest, Remove) {
1197 SmallString<64> BaseDir;
1198 SmallString<64> Paths[4];
1199 int fds[4];
1200 ASSERT_NO_ERROR(fs::createUniqueDirectory("fs_remove", BaseDir));
1201
1202 ASSERT_NO_ERROR(fs::create_directories(Twine(BaseDir) + "/foo/bar/baz"));
1203 ASSERT_NO_ERROR(fs::create_directories(Twine(BaseDir) + "/foo/bar/buzz"));
1204 ASSERT_NO_ERROR(fs::createUniqueFile(
1205 Twine(BaseDir) + "/foo/bar/baz/%%%%%%.tmp", fds[0], Paths[0]));
1206 ASSERT_NO_ERROR(fs::createUniqueFile(
1207 Twine(BaseDir) + "/foo/bar/baz/%%%%%%.tmp", fds[1], Paths[1]));
1208 ASSERT_NO_ERROR(fs::createUniqueFile(
1209 Twine(BaseDir) + "/foo/bar/buzz/%%%%%%.tmp", fds[2], Paths[2]));
1210 ASSERT_NO_ERROR(fs::createUniqueFile(
1211 Twine(BaseDir) + "/foo/bar/buzz/%%%%%%.tmp", fds[3], Paths[3]));
1212
1213 for (int fd : fds)
1214 ::close(fd);
1215
1216 EXPECT_TRUE(fs::exists(Twine(BaseDir) + "/foo/bar/baz"));
1217 EXPECT_TRUE(fs::exists(Twine(BaseDir) + "/foo/bar/buzz"));
1218 EXPECT_TRUE(fs::exists(Paths[0]));
1219 EXPECT_TRUE(fs::exists(Paths[1]));
1220 EXPECT_TRUE(fs::exists(Paths[2]));
1221 EXPECT_TRUE(fs::exists(Paths[3]));
1222
1223 ASSERT_NO_ERROR(fs::remove_directories("D:/footest"));
1224
1225 ASSERT_NO_ERROR(fs::remove_directories(BaseDir));
1226 ASSERT_FALSE(fs::exists(BaseDir));
1227 }
1228
1229 #ifdef _WIN32
TEST_F(FileSystemTest,CarriageReturn)1230 TEST_F(FileSystemTest, CarriageReturn) {
1231 SmallString<128> FilePathname(TestDirectory);
1232 std::error_code EC;
1233 path::append(FilePathname, "test");
1234
1235 {
1236 raw_fd_ostream File(FilePathname, EC, sys::fs::OF_Text);
1237 ASSERT_NO_ERROR(EC);
1238 File << '\n';
1239 }
1240 {
1241 auto Buf = MemoryBuffer::getFile(FilePathname.str());
1242 EXPECT_TRUE((bool)Buf);
1243 EXPECT_EQ(Buf.get()->getBuffer(), "\r\n");
1244 }
1245
1246 {
1247 raw_fd_ostream File(FilePathname, EC, sys::fs::OF_None);
1248 ASSERT_NO_ERROR(EC);
1249 File << '\n';
1250 }
1251 {
1252 auto Buf = MemoryBuffer::getFile(FilePathname.str());
1253 EXPECT_TRUE((bool)Buf);
1254 EXPECT_EQ(Buf.get()->getBuffer(), "\n");
1255 }
1256 ASSERT_NO_ERROR(fs::remove(Twine(FilePathname)));
1257 }
1258 #endif
1259
TEST_F(FileSystemTest,Resize)1260 TEST_F(FileSystemTest, Resize) {
1261 int FD;
1262 SmallString<64> TempPath;
1263 ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "temp", FD, TempPath));
1264 ASSERT_NO_ERROR(fs::resize_file(FD, 123));
1265 fs::file_status Status;
1266 ASSERT_NO_ERROR(fs::status(FD, Status));
1267 ASSERT_EQ(Status.getSize(), 123U);
1268 ::close(FD);
1269 ASSERT_NO_ERROR(fs::remove(TempPath));
1270 }
1271
TEST_F(FileSystemTest,MD5)1272 TEST_F(FileSystemTest, MD5) {
1273 int FD;
1274 SmallString<64> TempPath;
1275 ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "temp", FD, TempPath));
1276 StringRef Data("abcdefghijklmnopqrstuvwxyz");
1277 ASSERT_EQ(write(FD, Data.data(), Data.size()), static_cast<ssize_t>(Data.size()));
1278 lseek(FD, 0, SEEK_SET);
1279 auto Hash = fs::md5_contents(FD);
1280 ::close(FD);
1281 ASSERT_NO_ERROR(Hash.getError());
1282
1283 EXPECT_STREQ("c3fcd3d76192e4007dfb496cca67e13b", Hash->digest().c_str());
1284 }
1285
TEST_F(FileSystemTest,FileMapping)1286 TEST_F(FileSystemTest, FileMapping) {
1287 // Create a temp file.
1288 int FileDescriptor;
1289 SmallString<64> TempPath;
1290 ASSERT_NO_ERROR(
1291 fs::createTemporaryFile("prefix", "temp", FileDescriptor, TempPath));
1292 unsigned Size = 4096;
1293 ASSERT_NO_ERROR(fs::resize_file(FileDescriptor, Size));
1294
1295 // Map in temp file and add some content
1296 std::error_code EC;
1297 StringRef Val("hello there");
1298 {
1299 fs::mapped_file_region mfr(fs::convertFDToNativeFile(FileDescriptor),
1300 fs::mapped_file_region::readwrite, Size, 0, EC);
1301 ASSERT_NO_ERROR(EC);
1302 std::copy(Val.begin(), Val.end(), mfr.data());
1303 // Explicitly add a 0.
1304 mfr.data()[Val.size()] = 0;
1305 // Unmap temp file
1306 }
1307 ASSERT_EQ(close(FileDescriptor), 0);
1308
1309 // Map it back in read-only
1310 {
1311 int FD;
1312 EC = fs::openFileForRead(Twine(TempPath), FD);
1313 ASSERT_NO_ERROR(EC);
1314 fs::mapped_file_region mfr(fs::convertFDToNativeFile(FD),
1315 fs::mapped_file_region::readonly, Size, 0, EC);
1316 ASSERT_NO_ERROR(EC);
1317
1318 // Verify content
1319 EXPECT_EQ(StringRef(mfr.const_data()), Val);
1320
1321 // Unmap temp file
1322 fs::mapped_file_region m(fs::convertFDToNativeFile(FD),
1323 fs::mapped_file_region::readonly, Size, 0, EC);
1324 ASSERT_NO_ERROR(EC);
1325 ASSERT_EQ(close(FD), 0);
1326 }
1327 ASSERT_NO_ERROR(fs::remove(TempPath));
1328 }
1329
TEST(Support,NormalizePath)1330 TEST(Support, NormalizePath) {
1331 // Input, Expected Win, Expected Posix
1332 using TestTuple = std::tuple<const char *, const char *, const char *>;
1333 std::vector<TestTuple> Tests;
1334 Tests.emplace_back("a", "a", "a");
1335 Tests.emplace_back("a/b", "a\\b", "a/b");
1336 Tests.emplace_back("a\\b", "a\\b", "a/b");
1337 Tests.emplace_back("a\\\\b", "a\\\\b", "a//b");
1338 Tests.emplace_back("\\a", "\\a", "/a");
1339 Tests.emplace_back("a\\", "a\\", "a/");
1340 Tests.emplace_back("a\\t", "a\\t", "a/t");
1341
1342 for (auto &T : Tests) {
1343 SmallString<64> Win(std::get<0>(T));
1344 SmallString<64> Posix(Win);
1345 path::native(Win, path::Style::windows);
1346 path::native(Posix, path::Style::posix);
1347 EXPECT_EQ(std::get<1>(T), Win);
1348 EXPECT_EQ(std::get<2>(T), Posix);
1349 }
1350
1351 #if defined(_WIN32)
1352 SmallString<64> PathHome;
1353 path::home_directory(PathHome);
1354
1355 const char *Path7a = "~/aaa";
1356 SmallString<64> Path7(Path7a);
1357 path::native(Path7);
1358 EXPECT_TRUE(Path7.endswith("\\aaa"));
1359 EXPECT_TRUE(Path7.startswith(PathHome));
1360 EXPECT_EQ(Path7.size(), PathHome.size() + strlen(Path7a + 1));
1361
1362 const char *Path8a = "~";
1363 SmallString<64> Path8(Path8a);
1364 path::native(Path8);
1365 EXPECT_EQ(Path8, PathHome);
1366
1367 const char *Path9a = "~aaa";
1368 SmallString<64> Path9(Path9a);
1369 path::native(Path9);
1370 EXPECT_EQ(Path9, "~aaa");
1371
1372 const char *Path10a = "aaa/~/b";
1373 SmallString<64> Path10(Path10a);
1374 path::native(Path10);
1375 EXPECT_EQ(Path10, "aaa\\~\\b");
1376 #endif
1377 }
1378
TEST(Support,RemoveLeadingDotSlash)1379 TEST(Support, RemoveLeadingDotSlash) {
1380 StringRef Path1("././/foolz/wat");
1381 StringRef Path2("./////");
1382
1383 Path1 = path::remove_leading_dotslash(Path1);
1384 EXPECT_EQ(Path1, "foolz/wat");
1385 Path2 = path::remove_leading_dotslash(Path2);
1386 EXPECT_EQ(Path2, "");
1387 }
1388
remove_dots(StringRef path,bool remove_dot_dot,path::Style style)1389 static std::string remove_dots(StringRef path, bool remove_dot_dot,
1390 path::Style style) {
1391 SmallString<256> buffer(path);
1392 path::remove_dots(buffer, remove_dot_dot, style);
1393 return std::string(buffer.str());
1394 }
1395
TEST(Support,RemoveDots)1396 TEST(Support, RemoveDots) {
1397 EXPECT_EQ("foolz\\wat",
1398 remove_dots(".\\.\\\\foolz\\wat", false, path::Style::windows));
1399 EXPECT_EQ("", remove_dots(".\\\\\\\\\\", false, path::Style::windows));
1400
1401 EXPECT_EQ("a\\..\\b\\c",
1402 remove_dots(".\\a\\..\\b\\c", false, path::Style::windows));
1403 EXPECT_EQ("b\\c", remove_dots(".\\a\\..\\b\\c", true, path::Style::windows));
1404 EXPECT_EQ("c", remove_dots(".\\.\\c", true, path::Style::windows));
1405 EXPECT_EQ("..\\a\\c",
1406 remove_dots("..\\a\\b\\..\\c", true, path::Style::windows));
1407 EXPECT_EQ("..\\..\\a\\c",
1408 remove_dots("..\\..\\a\\b\\..\\c", true, path::Style::windows));
1409 EXPECT_EQ("C:\\a\\c", remove_dots("C:\\foo\\bar//..\\..\\a\\c", true,
1410 path::Style::windows));
1411
1412 // FIXME: These leading forward slashes are emergent behavior. VFS depends on
1413 // this behavior now.
1414 EXPECT_EQ("C:/bar",
1415 remove_dots("C:/foo/../bar", true, path::Style::windows));
1416 EXPECT_EQ("C:/foo\\bar",
1417 remove_dots("C:/foo/bar", true, path::Style::windows));
1418 EXPECT_EQ("C:/foo\\bar",
1419 remove_dots("C:/foo\\bar", true, path::Style::windows));
1420 EXPECT_EQ("/", remove_dots("/", true, path::Style::windows));
1421 EXPECT_EQ("C:/", remove_dots("C:/", true, path::Style::windows));
1422
1423 // Some clients of remove_dots expect it to remove trailing slashes. Again,
1424 // this is emergent behavior that VFS relies on, and not inherently part of
1425 // the specification.
1426 EXPECT_EQ("C:\\foo\\bar",
1427 remove_dots("C:\\foo\\bar\\", true, path::Style::windows));
1428 EXPECT_EQ("/foo/bar",
1429 remove_dots("/foo/bar/", true, path::Style::posix));
1430
1431 // A double separator is rewritten.
1432 EXPECT_EQ("C:/foo\\bar", remove_dots("C:/foo//bar", true, path::Style::windows));
1433
1434 SmallString<64> Path1(".\\.\\c");
1435 EXPECT_TRUE(path::remove_dots(Path1, true, path::Style::windows));
1436 EXPECT_EQ("c", Path1);
1437
1438 EXPECT_EQ("foolz/wat",
1439 remove_dots("././/foolz/wat", false, path::Style::posix));
1440 EXPECT_EQ("", remove_dots("./////", false, path::Style::posix));
1441
1442 EXPECT_EQ("a/../b/c", remove_dots("./a/../b/c", false, path::Style::posix));
1443 EXPECT_EQ("b/c", remove_dots("./a/../b/c", true, path::Style::posix));
1444 EXPECT_EQ("c", remove_dots("././c", true, path::Style::posix));
1445 EXPECT_EQ("../a/c", remove_dots("../a/b/../c", true, path::Style::posix));
1446 EXPECT_EQ("../../a/c",
1447 remove_dots("../../a/b/../c", true, path::Style::posix));
1448 EXPECT_EQ("/a/c", remove_dots("/../../a/c", true, path::Style::posix));
1449 EXPECT_EQ("/a/c",
1450 remove_dots("/../a/b//../././/c", true, path::Style::posix));
1451 EXPECT_EQ("/", remove_dots("/", true, path::Style::posix));
1452
1453 // FIXME: Leaving behind this double leading slash seems like a bug.
1454 EXPECT_EQ("//foo/bar",
1455 remove_dots("//foo/bar/", true, path::Style::posix));
1456
1457 SmallString<64> Path2("././c");
1458 EXPECT_TRUE(path::remove_dots(Path2, true, path::Style::posix));
1459 EXPECT_EQ("c", Path2);
1460 }
1461
TEST(Support,ReplacePathPrefix)1462 TEST(Support, ReplacePathPrefix) {
1463 SmallString<64> Path1("/foo");
1464 SmallString<64> Path2("/old/foo");
1465 SmallString<64> Path3("/oldnew/foo");
1466 SmallString<64> Path4("C:\\old/foo\\bar");
1467 SmallString<64> OldPrefix("/old");
1468 SmallString<64> OldPrefixSep("/old/");
1469 SmallString<64> OldPrefixWin("c:/oLD/F");
1470 SmallString<64> NewPrefix("/new");
1471 SmallString<64> NewPrefix2("/longernew");
1472 SmallString<64> EmptyPrefix("");
1473 bool Found;
1474
1475 SmallString<64> Path = Path1;
1476 Found = path::replace_path_prefix(Path, OldPrefix, NewPrefix);
1477 EXPECT_FALSE(Found);
1478 EXPECT_EQ(Path, "/foo");
1479 Path = Path2;
1480 Found = path::replace_path_prefix(Path, OldPrefix, NewPrefix);
1481 EXPECT_TRUE(Found);
1482 EXPECT_EQ(Path, "/new/foo");
1483 Path = Path2;
1484 Found = path::replace_path_prefix(Path, OldPrefix, NewPrefix2);
1485 EXPECT_TRUE(Found);
1486 EXPECT_EQ(Path, "/longernew/foo");
1487 Path = Path1;
1488 Found = path::replace_path_prefix(Path, EmptyPrefix, NewPrefix);
1489 EXPECT_TRUE(Found);
1490 EXPECT_EQ(Path, "/new/foo");
1491 Path = Path2;
1492 Found = path::replace_path_prefix(Path, OldPrefix, EmptyPrefix);
1493 EXPECT_TRUE(Found);
1494 EXPECT_EQ(Path, "/foo");
1495 Path = Path2;
1496 Found = path::replace_path_prefix(Path, OldPrefixSep, EmptyPrefix);
1497 EXPECT_TRUE(Found);
1498 EXPECT_EQ(Path, "foo");
1499 Path = Path3;
1500 Found = path::replace_path_prefix(Path, OldPrefix, NewPrefix);
1501 EXPECT_TRUE(Found);
1502 EXPECT_EQ(Path, "/newnew/foo");
1503 Path = Path3;
1504 Found = path::replace_path_prefix(Path, OldPrefix, NewPrefix2);
1505 EXPECT_TRUE(Found);
1506 EXPECT_EQ(Path, "/longernewnew/foo");
1507 Path = Path1;
1508 Found = path::replace_path_prefix(Path, EmptyPrefix, NewPrefix);
1509 EXPECT_TRUE(Found);
1510 EXPECT_EQ(Path, "/new/foo");
1511 Path = OldPrefix;
1512 Found = path::replace_path_prefix(Path, OldPrefix, NewPrefix);
1513 EXPECT_TRUE(Found);
1514 EXPECT_EQ(Path, "/new");
1515 Path = OldPrefixSep;
1516 Found = path::replace_path_prefix(Path, OldPrefix, NewPrefix);
1517 EXPECT_TRUE(Found);
1518 EXPECT_EQ(Path, "/new/");
1519 Path = OldPrefix;
1520 Found = path::replace_path_prefix(Path, OldPrefixSep, NewPrefix);
1521 EXPECT_FALSE(Found);
1522 EXPECT_EQ(Path, "/old");
1523 Path = Path4;
1524 Found = path::replace_path_prefix(Path, OldPrefixWin, NewPrefix,
1525 path::Style::windows);
1526 EXPECT_TRUE(Found);
1527 EXPECT_EQ(Path, "/newoo\\bar");
1528 Path = Path4;
1529 Found = path::replace_path_prefix(Path, OldPrefixWin, NewPrefix,
1530 path::Style::posix);
1531 EXPECT_FALSE(Found);
1532 EXPECT_EQ(Path, "C:\\old/foo\\bar");
1533 }
1534
TEST_F(FileSystemTest,OpenFileForRead)1535 TEST_F(FileSystemTest, OpenFileForRead) {
1536 // Create a temp file.
1537 int FileDescriptor;
1538 SmallString<64> TempPath;
1539 ASSERT_NO_ERROR(
1540 fs::createTemporaryFile("prefix", "temp", FileDescriptor, TempPath));
1541 FileRemover Cleanup(TempPath);
1542
1543 // Make sure it exists.
1544 ASSERT_TRUE(sys::fs::exists(Twine(TempPath)));
1545
1546 // Open the file for read
1547 int FileDescriptor2;
1548 SmallString<64> ResultPath;
1549 ASSERT_NO_ERROR(fs::openFileForRead(Twine(TempPath), FileDescriptor2,
1550 fs::OF_None, &ResultPath))
1551
1552 // If we succeeded, check that the paths are the same (modulo case):
1553 if (!ResultPath.empty()) {
1554 // The paths returned by createTemporaryFile and getPathFromOpenFD
1555 // should reference the same file on disk.
1556 fs::UniqueID D1, D2;
1557 ASSERT_NO_ERROR(fs::getUniqueID(Twine(TempPath), D1));
1558 ASSERT_NO_ERROR(fs::getUniqueID(Twine(ResultPath), D2));
1559 ASSERT_EQ(D1, D2);
1560 }
1561 ::close(FileDescriptor);
1562 ::close(FileDescriptor2);
1563
1564 #ifdef _WIN32
1565 // Since Windows Vista, file access time is not updated by default.
1566 // This is instead updated manually by openFileForRead.
1567 // https://blogs.technet.microsoft.com/filecab/2006/11/07/disabling-last-access-time-in-windows-vista-to-improve-ntfs-performance/
1568 // This part of the unit test is Windows specific as the updating of
1569 // access times can be disabled on Linux using /etc/fstab.
1570
1571 // Set access time to UNIX epoch.
1572 ASSERT_NO_ERROR(sys::fs::openFileForWrite(Twine(TempPath), FileDescriptor,
1573 fs::CD_OpenExisting));
1574 TimePoint<> Epoch(std::chrono::milliseconds(0));
1575 ASSERT_NO_ERROR(fs::setLastAccessAndModificationTime(FileDescriptor, Epoch));
1576 ::close(FileDescriptor);
1577
1578 // Open the file and ensure access time is updated, when forced.
1579 ASSERT_NO_ERROR(fs::openFileForRead(Twine(TempPath), FileDescriptor,
1580 fs::OF_UpdateAtime, &ResultPath));
1581
1582 sys::fs::file_status Status;
1583 ASSERT_NO_ERROR(sys::fs::status(FileDescriptor, Status));
1584 auto FileAccessTime = Status.getLastAccessedTime();
1585
1586 ASSERT_NE(Epoch, FileAccessTime);
1587 ::close(FileDescriptor);
1588
1589 // Ideally this test would include a case when ATime is not forced to update,
1590 // however the expected behaviour will differ depending on the configuration
1591 // of the Windows file system.
1592 #endif
1593 }
1594
createFileWithData(const Twine & Path,bool ShouldExistBefore,fs::CreationDisposition Disp,StringRef Data)1595 static void createFileWithData(const Twine &Path, bool ShouldExistBefore,
1596 fs::CreationDisposition Disp, StringRef Data) {
1597 int FD;
1598 ASSERT_EQ(ShouldExistBefore, fs::exists(Path));
1599 ASSERT_NO_ERROR(fs::openFileForWrite(Path, FD, Disp));
1600 FileDescriptorCloser Closer(FD);
1601 ASSERT_TRUE(fs::exists(Path));
1602
1603 ASSERT_EQ(Data.size(), (size_t)write(FD, Data.data(), Data.size()));
1604 }
1605
verifyFileContents(const Twine & Path,StringRef Contents)1606 static void verifyFileContents(const Twine &Path, StringRef Contents) {
1607 auto Buffer = MemoryBuffer::getFile(Path);
1608 ASSERT_TRUE((bool)Buffer);
1609 StringRef Data = Buffer.get()->getBuffer();
1610 ASSERT_EQ(Data, Contents);
1611 }
1612
TEST_F(FileSystemTest,CreateNew)1613 TEST_F(FileSystemTest, CreateNew) {
1614 int FD;
1615 Optional<FileDescriptorCloser> Closer;
1616
1617 // Succeeds if the file does not exist.
1618 ASSERT_FALSE(fs::exists(NonExistantFile));
1619 ASSERT_NO_ERROR(fs::openFileForWrite(NonExistantFile, FD, fs::CD_CreateNew));
1620 ASSERT_TRUE(fs::exists(NonExistantFile));
1621
1622 FileRemover Cleanup(NonExistantFile);
1623 Closer.emplace(FD);
1624
1625 // And creates a file of size 0.
1626 sys::fs::file_status Status;
1627 ASSERT_NO_ERROR(sys::fs::status(FD, Status));
1628 EXPECT_EQ(0ULL, Status.getSize());
1629
1630 // Close this first, before trying to re-open the file.
1631 Closer.reset();
1632
1633 // But fails if the file does exist.
1634 ASSERT_ERROR(fs::openFileForWrite(NonExistantFile, FD, fs::CD_CreateNew));
1635 }
1636
TEST_F(FileSystemTest,CreateAlways)1637 TEST_F(FileSystemTest, CreateAlways) {
1638 int FD;
1639 Optional<FileDescriptorCloser> Closer;
1640
1641 // Succeeds if the file does not exist.
1642 ASSERT_FALSE(fs::exists(NonExistantFile));
1643 ASSERT_NO_ERROR(
1644 fs::openFileForWrite(NonExistantFile, FD, fs::CD_CreateAlways));
1645
1646 Closer.emplace(FD);
1647
1648 ASSERT_TRUE(fs::exists(NonExistantFile));
1649
1650 FileRemover Cleanup(NonExistantFile);
1651
1652 // And creates a file of size 0.
1653 uint64_t FileSize;
1654 ASSERT_NO_ERROR(sys::fs::file_size(NonExistantFile, FileSize));
1655 ASSERT_EQ(0ULL, FileSize);
1656
1657 // If we write some data to it re-create it with CreateAlways, it succeeds and
1658 // truncates to 0 bytes.
1659 ASSERT_EQ(4, write(FD, "Test", 4));
1660
1661 Closer.reset();
1662
1663 ASSERT_NO_ERROR(sys::fs::file_size(NonExistantFile, FileSize));
1664 ASSERT_EQ(4ULL, FileSize);
1665
1666 ASSERT_NO_ERROR(
1667 fs::openFileForWrite(NonExistantFile, FD, fs::CD_CreateAlways));
1668 Closer.emplace(FD);
1669 ASSERT_NO_ERROR(sys::fs::file_size(NonExistantFile, FileSize));
1670 ASSERT_EQ(0ULL, FileSize);
1671 }
1672
TEST_F(FileSystemTest,OpenExisting)1673 TEST_F(FileSystemTest, OpenExisting) {
1674 int FD;
1675
1676 // Fails if the file does not exist.
1677 ASSERT_FALSE(fs::exists(NonExistantFile));
1678 ASSERT_ERROR(fs::openFileForWrite(NonExistantFile, FD, fs::CD_OpenExisting));
1679 ASSERT_FALSE(fs::exists(NonExistantFile));
1680
1681 // Make a dummy file now so that we can try again when the file does exist.
1682 createFileWithData(NonExistantFile, false, fs::CD_CreateNew, "Fizz");
1683 FileRemover Cleanup(NonExistantFile);
1684 uint64_t FileSize;
1685 ASSERT_NO_ERROR(sys::fs::file_size(NonExistantFile, FileSize));
1686 ASSERT_EQ(4ULL, FileSize);
1687
1688 // If we re-create it with different data, it overwrites rather than
1689 // appending.
1690 createFileWithData(NonExistantFile, true, fs::CD_OpenExisting, "Buzz");
1691 verifyFileContents(NonExistantFile, "Buzz");
1692 }
1693
TEST_F(FileSystemTest,OpenAlways)1694 TEST_F(FileSystemTest, OpenAlways) {
1695 // Succeeds if the file does not exist.
1696 createFileWithData(NonExistantFile, false, fs::CD_OpenAlways, "Fizz");
1697 FileRemover Cleanup(NonExistantFile);
1698 uint64_t FileSize;
1699 ASSERT_NO_ERROR(sys::fs::file_size(NonExistantFile, FileSize));
1700 ASSERT_EQ(4ULL, FileSize);
1701
1702 // Now re-open it and write again, verifying the contents get over-written.
1703 createFileWithData(NonExistantFile, true, fs::CD_OpenAlways, "Bu");
1704 verifyFileContents(NonExistantFile, "Buzz");
1705 }
1706
TEST_F(FileSystemTest,AppendSetsCorrectFileOffset)1707 TEST_F(FileSystemTest, AppendSetsCorrectFileOffset) {
1708 fs::CreationDisposition Disps[] = {fs::CD_CreateAlways, fs::CD_OpenAlways,
1709 fs::CD_OpenExisting};
1710
1711 // Write some data and re-open it with every possible disposition (this is a
1712 // hack that shouldn't work, but is left for compatibility. OF_Append
1713 // overrides
1714 // the specified disposition.
1715 for (fs::CreationDisposition Disp : Disps) {
1716 int FD;
1717 Optional<FileDescriptorCloser> Closer;
1718
1719 createFileWithData(NonExistantFile, false, fs::CD_CreateNew, "Fizz");
1720
1721 FileRemover Cleanup(NonExistantFile);
1722
1723 uint64_t FileSize;
1724 ASSERT_NO_ERROR(sys::fs::file_size(NonExistantFile, FileSize));
1725 ASSERT_EQ(4ULL, FileSize);
1726 ASSERT_NO_ERROR(
1727 fs::openFileForWrite(NonExistantFile, FD, Disp, fs::OF_Append));
1728 Closer.emplace(FD);
1729 ASSERT_NO_ERROR(sys::fs::file_size(NonExistantFile, FileSize));
1730 ASSERT_EQ(4ULL, FileSize);
1731
1732 ASSERT_EQ(4, write(FD, "Buzz", 4));
1733 Closer.reset();
1734
1735 verifyFileContents(NonExistantFile, "FizzBuzz");
1736 }
1737 }
1738
verifyRead(int FD,StringRef Data,bool ShouldSucceed)1739 static void verifyRead(int FD, StringRef Data, bool ShouldSucceed) {
1740 std::vector<char> Buffer;
1741 Buffer.resize(Data.size());
1742 int Result = ::read(FD, Buffer.data(), Buffer.size());
1743 if (ShouldSucceed) {
1744 ASSERT_EQ((size_t)Result, Data.size());
1745 ASSERT_EQ(Data, StringRef(Buffer.data(), Buffer.size()));
1746 } else {
1747 ASSERT_EQ(-1, Result);
1748 ASSERT_EQ(EBADF, errno);
1749 }
1750 }
1751
verifyWrite(int FD,StringRef Data,bool ShouldSucceed)1752 static void verifyWrite(int FD, StringRef Data, bool ShouldSucceed) {
1753 int Result = ::write(FD, Data.data(), Data.size());
1754 if (ShouldSucceed)
1755 ASSERT_EQ((size_t)Result, Data.size());
1756 else {
1757 ASSERT_EQ(-1, Result);
1758 ASSERT_EQ(EBADF, errno);
1759 }
1760 }
1761
TEST_F(FileSystemTest,ReadOnlyFileCantWrite)1762 TEST_F(FileSystemTest, ReadOnlyFileCantWrite) {
1763 createFileWithData(NonExistantFile, false, fs::CD_CreateNew, "Fizz");
1764 FileRemover Cleanup(NonExistantFile);
1765
1766 int FD;
1767 ASSERT_NO_ERROR(fs::openFileForRead(NonExistantFile, FD));
1768 FileDescriptorCloser Closer(FD);
1769
1770 verifyWrite(FD, "Buzz", false);
1771 verifyRead(FD, "Fizz", true);
1772 }
1773
TEST_F(FileSystemTest,WriteOnlyFileCantRead)1774 TEST_F(FileSystemTest, WriteOnlyFileCantRead) {
1775 createFileWithData(NonExistantFile, false, fs::CD_CreateNew, "Fizz");
1776 FileRemover Cleanup(NonExistantFile);
1777
1778 int FD;
1779 ASSERT_NO_ERROR(
1780 fs::openFileForWrite(NonExistantFile, FD, fs::CD_OpenExisting));
1781 FileDescriptorCloser Closer(FD);
1782 verifyRead(FD, "Fizz", false);
1783 verifyWrite(FD, "Buzz", true);
1784 }
1785
TEST_F(FileSystemTest,ReadWriteFileCanReadOrWrite)1786 TEST_F(FileSystemTest, ReadWriteFileCanReadOrWrite) {
1787 createFileWithData(NonExistantFile, false, fs::CD_CreateNew, "Fizz");
1788 FileRemover Cleanup(NonExistantFile);
1789
1790 int FD;
1791 ASSERT_NO_ERROR(fs::openFileForReadWrite(NonExistantFile, FD,
1792 fs::CD_OpenExisting, fs::OF_None));
1793 FileDescriptorCloser Closer(FD);
1794 verifyRead(FD, "Fizz", true);
1795 verifyWrite(FD, "Buzz", true);
1796 }
1797
TEST_F(FileSystemTest,readNativeFile)1798 TEST_F(FileSystemTest, readNativeFile) {
1799 createFileWithData(NonExistantFile, false, fs::CD_CreateNew, "01234");
1800 FileRemover Cleanup(NonExistantFile);
1801 const auto &Read = [&](size_t ToRead) -> Expected<std::string> {
1802 std::string Buf(ToRead, '?');
1803 Expected<fs::file_t> FD = fs::openNativeFileForRead(NonExistantFile);
1804 if (!FD)
1805 return FD.takeError();
1806 auto Close = make_scope_exit([&] { fs::closeFile(*FD); });
1807 if (Expected<size_t> BytesRead = fs::readNativeFile(
1808 *FD, makeMutableArrayRef(&*Buf.begin(), Buf.size())))
1809 return Buf.substr(0, *BytesRead);
1810 else
1811 return BytesRead.takeError();
1812 };
1813 EXPECT_THAT_EXPECTED(Read(5), HasValue("01234"));
1814 EXPECT_THAT_EXPECTED(Read(3), HasValue("012"));
1815 EXPECT_THAT_EXPECTED(Read(6), HasValue("01234"));
1816 }
1817
TEST_F(FileSystemTest,readNativeFileSlice)1818 TEST_F(FileSystemTest, readNativeFileSlice) {
1819 createFileWithData(NonExistantFile, false, fs::CD_CreateNew, "01234");
1820 FileRemover Cleanup(NonExistantFile);
1821 Expected<fs::file_t> FD = fs::openNativeFileForRead(NonExistantFile);
1822 ASSERT_THAT_EXPECTED(FD, Succeeded());
1823 auto Close = make_scope_exit([&] { fs::closeFile(*FD); });
1824 const auto &Read = [&](size_t Offset,
1825 size_t ToRead) -> Expected<std::string> {
1826 std::string Buf(ToRead, '?');
1827 if (Expected<size_t> BytesRead = fs::readNativeFileSlice(
1828 *FD, makeMutableArrayRef(&*Buf.begin(), Buf.size()), Offset))
1829 return Buf.substr(0, *BytesRead);
1830 else
1831 return BytesRead.takeError();
1832 };
1833 EXPECT_THAT_EXPECTED(Read(0, 5), HasValue("01234"));
1834 EXPECT_THAT_EXPECTED(Read(0, 3), HasValue("012"));
1835 EXPECT_THAT_EXPECTED(Read(2, 3), HasValue("234"));
1836 EXPECT_THAT_EXPECTED(Read(0, 6), HasValue("01234"));
1837 EXPECT_THAT_EXPECTED(Read(2, 6), HasValue("234"));
1838 EXPECT_THAT_EXPECTED(Read(5, 5), HasValue(""));
1839 }
1840
TEST_F(FileSystemTest,is_local)1841 TEST_F(FileSystemTest, is_local) {
1842 bool TestDirectoryIsLocal;
1843 ASSERT_NO_ERROR(fs::is_local(TestDirectory, TestDirectoryIsLocal));
1844 EXPECT_EQ(TestDirectoryIsLocal, fs::is_local(TestDirectory));
1845
1846 int FD;
1847 SmallString<128> TempPath;
1848 ASSERT_NO_ERROR(
1849 fs::createUniqueFile(Twine(TestDirectory) + "/temp", FD, TempPath));
1850 FileRemover Cleanup(TempPath);
1851
1852 // Make sure it exists.
1853 ASSERT_TRUE(sys::fs::exists(Twine(TempPath)));
1854
1855 bool TempFileIsLocal;
1856 ASSERT_NO_ERROR(fs::is_local(FD, TempFileIsLocal));
1857 EXPECT_EQ(TempFileIsLocal, fs::is_local(FD));
1858 ::close(FD);
1859
1860 // Expect that the file and its parent directory are equally local or equally
1861 // remote.
1862 EXPECT_EQ(TestDirectoryIsLocal, TempFileIsLocal);
1863 }
1864
TEST_F(FileSystemTest,getUmask)1865 TEST_F(FileSystemTest, getUmask) {
1866 #ifdef _WIN32
1867 EXPECT_EQ(fs::getUmask(), 0U) << "Should always be 0 on Windows.";
1868 #else
1869 unsigned OldMask = ::umask(0022);
1870 unsigned CurrentMask = fs::getUmask();
1871 EXPECT_EQ(CurrentMask, 0022U)
1872 << "getUmask() didn't return previously set umask()";
1873 EXPECT_EQ(::umask(OldMask), 0022U) << "getUmask() may have changed umask()";
1874 #endif
1875 }
1876
TEST_F(FileSystemTest,RespectUmask)1877 TEST_F(FileSystemTest, RespectUmask) {
1878 #ifndef _WIN32
1879 unsigned OldMask = ::umask(0022);
1880
1881 int FD;
1882 SmallString<128> TempPath;
1883 ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "temp", FD, TempPath));
1884
1885 fs::perms AllRWE = static_cast<fs::perms>(0777);
1886
1887 ASSERT_NO_ERROR(fs::setPermissions(TempPath, AllRWE));
1888
1889 ErrorOr<fs::perms> Perms = fs::getPermissions(TempPath);
1890 ASSERT_TRUE(!!Perms);
1891 EXPECT_EQ(Perms.get(), AllRWE) << "Should have ignored umask by default";
1892
1893 ASSERT_NO_ERROR(fs::setPermissions(TempPath, AllRWE));
1894
1895 Perms = fs::getPermissions(TempPath);
1896 ASSERT_TRUE(!!Perms);
1897 EXPECT_EQ(Perms.get(), AllRWE) << "Should have ignored umask";
1898
1899 ASSERT_NO_ERROR(
1900 fs::setPermissions(FD, static_cast<fs::perms>(AllRWE & ~fs::getUmask())));
1901 Perms = fs::getPermissions(TempPath);
1902 ASSERT_TRUE(!!Perms);
1903 EXPECT_EQ(Perms.get(), static_cast<fs::perms>(0755))
1904 << "Did not respect umask";
1905
1906 (void)::umask(0057);
1907
1908 ASSERT_NO_ERROR(
1909 fs::setPermissions(FD, static_cast<fs::perms>(AllRWE & ~fs::getUmask())));
1910 Perms = fs::getPermissions(TempPath);
1911 ASSERT_TRUE(!!Perms);
1912 EXPECT_EQ(Perms.get(), static_cast<fs::perms>(0720))
1913 << "Did not respect umask";
1914
1915 (void)::umask(OldMask);
1916 (void)::close(FD);
1917 #endif
1918 }
1919
TEST_F(FileSystemTest,set_current_path)1920 TEST_F(FileSystemTest, set_current_path) {
1921 SmallString<128> path;
1922
1923 ASSERT_NO_ERROR(fs::current_path(path));
1924 ASSERT_NE(TestDirectory, path);
1925
1926 struct RestorePath {
1927 SmallString<128> path;
1928 RestorePath(const SmallString<128> &path) : path(path) {}
1929 ~RestorePath() { fs::set_current_path(path); }
1930 } restore_path(path);
1931
1932 ASSERT_NO_ERROR(fs::set_current_path(TestDirectory));
1933
1934 ASSERT_NO_ERROR(fs::current_path(path));
1935
1936 fs::UniqueID D1, D2;
1937 ASSERT_NO_ERROR(fs::getUniqueID(TestDirectory, D1));
1938 ASSERT_NO_ERROR(fs::getUniqueID(path, D2));
1939 ASSERT_EQ(D1, D2) << "D1: " << TestDirectory << "\nD2: " << path;
1940 }
1941
TEST_F(FileSystemTest,permissions)1942 TEST_F(FileSystemTest, permissions) {
1943 int FD;
1944 SmallString<64> TempPath;
1945 ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "temp", FD, TempPath));
1946 FileRemover Cleanup(TempPath);
1947
1948 // Make sure it exists.
1949 ASSERT_TRUE(fs::exists(Twine(TempPath)));
1950
1951 auto CheckPermissions = [&](fs::perms Expected) {
1952 ErrorOr<fs::perms> Actual = fs::getPermissions(TempPath);
1953 return Actual && *Actual == Expected;
1954 };
1955
1956 std::error_code NoError;
1957 EXPECT_EQ(fs::setPermissions(TempPath, fs::all_all), NoError);
1958 EXPECT_TRUE(CheckPermissions(fs::all_all));
1959
1960 EXPECT_EQ(fs::setPermissions(TempPath, fs::all_read | fs::all_exe), NoError);
1961 EXPECT_TRUE(CheckPermissions(fs::all_read | fs::all_exe));
1962
1963 #if defined(_WIN32)
1964 fs::perms ReadOnly = fs::all_read | fs::all_exe;
1965 EXPECT_EQ(fs::setPermissions(TempPath, fs::no_perms), NoError);
1966 EXPECT_TRUE(CheckPermissions(ReadOnly));
1967
1968 EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_read), NoError);
1969 EXPECT_TRUE(CheckPermissions(ReadOnly));
1970
1971 EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_write), NoError);
1972 EXPECT_TRUE(CheckPermissions(fs::all_all));
1973
1974 EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_exe), NoError);
1975 EXPECT_TRUE(CheckPermissions(ReadOnly));
1976
1977 EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_all), NoError);
1978 EXPECT_TRUE(CheckPermissions(fs::all_all));
1979
1980 EXPECT_EQ(fs::setPermissions(TempPath, fs::group_read), NoError);
1981 EXPECT_TRUE(CheckPermissions(ReadOnly));
1982
1983 EXPECT_EQ(fs::setPermissions(TempPath, fs::group_write), NoError);
1984 EXPECT_TRUE(CheckPermissions(fs::all_all));
1985
1986 EXPECT_EQ(fs::setPermissions(TempPath, fs::group_exe), NoError);
1987 EXPECT_TRUE(CheckPermissions(ReadOnly));
1988
1989 EXPECT_EQ(fs::setPermissions(TempPath, fs::group_all), NoError);
1990 EXPECT_TRUE(CheckPermissions(fs::all_all));
1991
1992 EXPECT_EQ(fs::setPermissions(TempPath, fs::others_read), NoError);
1993 EXPECT_TRUE(CheckPermissions(ReadOnly));
1994
1995 EXPECT_EQ(fs::setPermissions(TempPath, fs::others_write), NoError);
1996 EXPECT_TRUE(CheckPermissions(fs::all_all));
1997
1998 EXPECT_EQ(fs::setPermissions(TempPath, fs::others_exe), NoError);
1999 EXPECT_TRUE(CheckPermissions(ReadOnly));
2000
2001 EXPECT_EQ(fs::setPermissions(TempPath, fs::others_all), NoError);
2002 EXPECT_TRUE(CheckPermissions(fs::all_all));
2003
2004 EXPECT_EQ(fs::setPermissions(TempPath, fs::all_read), NoError);
2005 EXPECT_TRUE(CheckPermissions(ReadOnly));
2006
2007 EXPECT_EQ(fs::setPermissions(TempPath, fs::all_write), NoError);
2008 EXPECT_TRUE(CheckPermissions(fs::all_all));
2009
2010 EXPECT_EQ(fs::setPermissions(TempPath, fs::all_exe), NoError);
2011 EXPECT_TRUE(CheckPermissions(ReadOnly));
2012
2013 EXPECT_EQ(fs::setPermissions(TempPath, fs::set_uid_on_exe), NoError);
2014 EXPECT_TRUE(CheckPermissions(ReadOnly));
2015
2016 EXPECT_EQ(fs::setPermissions(TempPath, fs::set_gid_on_exe), NoError);
2017 EXPECT_TRUE(CheckPermissions(ReadOnly));
2018
2019 EXPECT_EQ(fs::setPermissions(TempPath, fs::sticky_bit), NoError);
2020 EXPECT_TRUE(CheckPermissions(ReadOnly));
2021
2022 EXPECT_EQ(fs::setPermissions(TempPath, fs::set_uid_on_exe |
2023 fs::set_gid_on_exe |
2024 fs::sticky_bit),
2025 NoError);
2026 EXPECT_TRUE(CheckPermissions(ReadOnly));
2027
2028 EXPECT_EQ(fs::setPermissions(TempPath, ReadOnly | fs::set_uid_on_exe |
2029 fs::set_gid_on_exe |
2030 fs::sticky_bit),
2031 NoError);
2032 EXPECT_TRUE(CheckPermissions(ReadOnly));
2033
2034 EXPECT_EQ(fs::setPermissions(TempPath, fs::all_perms), NoError);
2035 EXPECT_TRUE(CheckPermissions(fs::all_all));
2036 #else
2037 EXPECT_EQ(fs::setPermissions(TempPath, fs::no_perms), NoError);
2038 EXPECT_TRUE(CheckPermissions(fs::no_perms));
2039
2040 EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_read), NoError);
2041 EXPECT_TRUE(CheckPermissions(fs::owner_read));
2042
2043 EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_write), NoError);
2044 EXPECT_TRUE(CheckPermissions(fs::owner_write));
2045
2046 EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_exe), NoError);
2047 EXPECT_TRUE(CheckPermissions(fs::owner_exe));
2048
2049 EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_all), NoError);
2050 EXPECT_TRUE(CheckPermissions(fs::owner_all));
2051
2052 EXPECT_EQ(fs::setPermissions(TempPath, fs::group_read), NoError);
2053 EXPECT_TRUE(CheckPermissions(fs::group_read));
2054
2055 EXPECT_EQ(fs::setPermissions(TempPath, fs::group_write), NoError);
2056 EXPECT_TRUE(CheckPermissions(fs::group_write));
2057
2058 EXPECT_EQ(fs::setPermissions(TempPath, fs::group_exe), NoError);
2059 EXPECT_TRUE(CheckPermissions(fs::group_exe));
2060
2061 EXPECT_EQ(fs::setPermissions(TempPath, fs::group_all), NoError);
2062 EXPECT_TRUE(CheckPermissions(fs::group_all));
2063
2064 EXPECT_EQ(fs::setPermissions(TempPath, fs::others_read), NoError);
2065 EXPECT_TRUE(CheckPermissions(fs::others_read));
2066
2067 EXPECT_EQ(fs::setPermissions(TempPath, fs::others_write), NoError);
2068 EXPECT_TRUE(CheckPermissions(fs::others_write));
2069
2070 EXPECT_EQ(fs::setPermissions(TempPath, fs::others_exe), NoError);
2071 EXPECT_TRUE(CheckPermissions(fs::others_exe));
2072
2073 EXPECT_EQ(fs::setPermissions(TempPath, fs::others_all), NoError);
2074 EXPECT_TRUE(CheckPermissions(fs::others_all));
2075
2076 EXPECT_EQ(fs::setPermissions(TempPath, fs::all_read), NoError);
2077 EXPECT_TRUE(CheckPermissions(fs::all_read));
2078
2079 EXPECT_EQ(fs::setPermissions(TempPath, fs::all_write), NoError);
2080 EXPECT_TRUE(CheckPermissions(fs::all_write));
2081
2082 EXPECT_EQ(fs::setPermissions(TempPath, fs::all_exe), NoError);
2083 EXPECT_TRUE(CheckPermissions(fs::all_exe));
2084
2085 EXPECT_EQ(fs::setPermissions(TempPath, fs::set_uid_on_exe), NoError);
2086 EXPECT_TRUE(CheckPermissions(fs::set_uid_on_exe));
2087
2088 // On FreeBSD the group id for the temporary file is taken from the parent
2089 // directory, but setting the setgid bit requires the file group to match the
2090 // current effecitive group ID. Otherwise we receive an EPERM error.
2091 // This might also affect other operating systems but most will set the group
2092 // ID to the current effective group ID so this works just fine.
2093 EXPECT_EQ(chown(TempPath.c_str(), geteuid(), getegid()), 0);
2094
2095 EXPECT_NO_ERROR(fs::setPermissions(TempPath, fs::set_gid_on_exe));
2096 EXPECT_TRUE(CheckPermissions(fs::set_gid_on_exe));
2097
2098 // Modern BSDs require root to set the sticky bit on files.
2099 // AIX and Solaris without root will mask off (i.e., lose) the sticky bit
2100 // on files.
2101 #if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && \
2102 !defined(_AIX) && !(defined(__sun__) && defined(__svr4__))
2103 EXPECT_EQ(fs::setPermissions(TempPath, fs::sticky_bit), NoError);
2104 EXPECT_TRUE(CheckPermissions(fs::sticky_bit));
2105
2106 EXPECT_EQ(fs::setPermissions(TempPath, fs::set_uid_on_exe |
2107 fs::set_gid_on_exe |
2108 fs::sticky_bit),
2109 NoError);
2110 EXPECT_TRUE(CheckPermissions(fs::set_uid_on_exe | fs::set_gid_on_exe |
2111 fs::sticky_bit));
2112
2113 EXPECT_EQ(fs::setPermissions(TempPath, fs::all_read | fs::set_uid_on_exe |
2114 fs::set_gid_on_exe |
2115 fs::sticky_bit),
2116 NoError);
2117 EXPECT_TRUE(CheckPermissions(fs::all_read | fs::set_uid_on_exe |
2118 fs::set_gid_on_exe | fs::sticky_bit));
2119
2120 EXPECT_NO_ERROR(fs::setPermissions(TempPath, fs::all_perms));
2121 EXPECT_TRUE(CheckPermissions(fs::all_perms));
2122 #endif // !FreeBSD && !NetBSD && !OpenBSD && !AIX
2123
2124 EXPECT_NO_ERROR(fs::setPermissions(TempPath, fs::all_perms & ~fs::sticky_bit));
2125 EXPECT_TRUE(CheckPermissions(fs::all_perms & ~fs::sticky_bit));
2126 #endif
2127 }
2128
2129 #ifdef _WIN32
TEST_F(FileSystemTest,widenPath)2130 TEST_F(FileSystemTest, widenPath) {
2131 const std::wstring LongPathPrefix(L"\\\\?\\");
2132
2133 // Test that the length limit is checked against the UTF-16 length and not the
2134 // UTF-8 length.
2135 std::string Input("C:\\foldername\\");
2136 const std::string Pi("\xcf\x80"); // UTF-8 lower case pi.
2137 // Add Pi up to the MAX_PATH limit.
2138 const size_t NumChars = MAX_PATH - Input.size() - 1;
2139 for (size_t i = 0; i < NumChars; ++i)
2140 Input += Pi;
2141 // Check that UTF-8 length already exceeds MAX_PATH.
2142 EXPECT_TRUE(Input.size() > MAX_PATH);
2143 SmallVector<wchar_t, MAX_PATH + 16> Result;
2144 ASSERT_NO_ERROR(windows::widenPath(Input, Result));
2145 // Result should not start with the long path prefix.
2146 EXPECT_TRUE(std::wmemcmp(Result.data(), LongPathPrefix.c_str(),
2147 LongPathPrefix.size()) != 0);
2148 EXPECT_EQ(Result.size(), (size_t)MAX_PATH - 1);
2149
2150 // Add another Pi to exceed the MAX_PATH limit.
2151 Input += Pi;
2152 // Construct the expected result.
2153 SmallVector<wchar_t, MAX_PATH + 16> Expected;
2154 ASSERT_NO_ERROR(windows::UTF8ToUTF16(Input, Expected));
2155 Expected.insert(Expected.begin(), LongPathPrefix.begin(),
2156 LongPathPrefix.end());
2157
2158 ASSERT_NO_ERROR(windows::widenPath(Input, Result));
2159 EXPECT_EQ(Result, Expected);
2160
2161 // Test that UNC paths are handled correctly.
2162 const std::string ShareName("\\\\sharename\\");
2163 const std::string FileName("\\filename");
2164 // Initialize directory name so that the input is within the MAX_PATH limit.
2165 const char DirChar = 'x';
2166 std::string DirName(MAX_PATH - ShareName.size() - FileName.size() - 1,
2167 DirChar);
2168
2169 Input = ShareName + DirName + FileName;
2170 ASSERT_NO_ERROR(windows::widenPath(Input, Result));
2171 // Result should not start with the long path prefix.
2172 EXPECT_TRUE(std::wmemcmp(Result.data(), LongPathPrefix.c_str(),
2173 LongPathPrefix.size()) != 0);
2174 EXPECT_EQ(Result.size(), (size_t)MAX_PATH - 1);
2175
2176 // Extend the directory name so the input exceeds the MAX_PATH limit.
2177 DirName += DirChar;
2178 Input = ShareName + DirName + FileName;
2179 // Construct the expected result.
2180 ASSERT_NO_ERROR(windows::UTF8ToUTF16(StringRef(Input).substr(2), Expected));
2181 const std::wstring UNCPrefix(LongPathPrefix + L"UNC\\");
2182 Expected.insert(Expected.begin(), UNCPrefix.begin(), UNCPrefix.end());
2183
2184 ASSERT_NO_ERROR(windows::widenPath(Input, Result));
2185 EXPECT_EQ(Result, Expected);
2186
2187 // Check that Unix separators are handled correctly.
2188 std::replace(Input.begin(), Input.end(), '\\', '/');
2189 ASSERT_NO_ERROR(windows::widenPath(Input, Result));
2190 EXPECT_EQ(Result, Expected);
2191
2192 // Check the removal of "dots".
2193 Input = ShareName + DirName + "\\.\\foo\\.\\.." + FileName;
2194 ASSERT_NO_ERROR(windows::widenPath(Input, Result));
2195 EXPECT_EQ(Result, Expected);
2196 }
2197 #endif
2198
2199 } // anonymous namespace
2200