Skip to content

Commit f77cf42

Browse files
authored
Merge pull request #11 from JDevlieghere/cherrypick/virtualfilesystem
[VirtualFileSystem] Support virtual working directory in the RedirectingFS
2 parents bcaa372 + ff03dd2 commit f77cf42

File tree

5 files changed

+301
-33
lines changed

5 files changed

+301
-33
lines changed

llvm/include/llvm/Support/VirtualFileSystem.h

+22-4
Original file line numberDiff line numberDiff line change
@@ -343,15 +343,24 @@ class OverlayFileSystem : public FileSystem {
343343

344344
using iterator = FileSystemList::reverse_iterator;
345345
using const_iterator = FileSystemList::const_reverse_iterator;
346+
using reverse_iterator = FileSystemList::iterator;
347+
using const_reverse_iterator = FileSystemList::const_iterator;
346348

347349
/// Get an iterator pointing to the most recently added file system.
348350
iterator overlays_begin() { return FSList.rbegin(); }
349351
const_iterator overlays_begin() const { return FSList.rbegin(); }
350352

351-
/// Get an iterator pointing one-past the least recently added file
352-
/// system.
353+
/// Get an iterator pointing one-past the least recently added file system.
353354
iterator overlays_end() { return FSList.rend(); }
354355
const_iterator overlays_end() const { return FSList.rend(); }
356+
357+
/// Get an iterator pointing to the least recently added file system.
358+
reverse_iterator overlays_rbegin() { return FSList.begin(); }
359+
const_reverse_iterator overlays_rbegin() const { return FSList.begin(); }
360+
361+
/// Get an iterator pointing one-past the most recently added file system.
362+
reverse_iterator overlays_rend() { return FSList.end(); }
363+
const_reverse_iterator overlays_rend() const { return FSList.end(); }
355364
};
356365

357366
/// By default, this delegates all calls to the underlying file system. This
@@ -638,9 +647,19 @@ class RedirectingFileSystem : public vfs::FileSystem {
638647
friend class VFSFromYamlDirIterImpl;
639648
friend class RedirectingFileSystemParser;
640649

650+
bool shouldUseExternalFS() const {
651+
return ExternalFSValidWD && IsFallthrough;
652+
}
653+
641654
/// The root(s) of the virtual file system.
642655
std::vector<std::unique_ptr<Entry>> Roots;
643656

657+
/// The current working directory of the file system.
658+
std::string WorkingDirectory;
659+
660+
/// Whether the current working directory is valid for the external FS.
661+
bool ExternalFSValidWD = false;
662+
644663
/// The file system to use for external references.
645664
IntrusiveRefCntPtr<FileSystem> ExternalFS;
646665

@@ -680,8 +699,7 @@ class RedirectingFileSystem : public vfs::FileSystem {
680699
true;
681700
#endif
682701

683-
RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> ExternalFS)
684-
: ExternalFS(std::move(ExternalFS)) {}
702+
RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> ExternalFS);
685703

686704
/// Looks up the path <tt>[Start, End)</tt> in \p From, possibly
687705
/// recursing into the contents of \p From if it is a directory.

llvm/lib/Support/Path.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -855,11 +855,11 @@ void make_absolute(const Twine &current_directory,
855855
StringRef p(path.data(), path.size());
856856

857857
bool rootDirectory = path::has_root_directory(p);
858-
bool rootName =
859-
(real_style(Style::native) != Style::windows) || path::has_root_name(p);
858+
bool rootName = path::has_root_name(p);
860859

861860
// Already absolute.
862-
if (rootName && rootDirectory)
861+
if ((rootName || real_style(Style::native) != Style::windows) &&
862+
rootDirectory)
863863
return;
864864

865865
// All of the following conditions will need the current directory.

llvm/lib/Support/VirtualFileSystem.cpp

+40-18
Original file line numberDiff line numberDiff line change
@@ -986,6 +986,16 @@ std::error_code InMemoryFileSystem::isLocal(const Twine &Path, bool &Result) {
986986
// RedirectingFileSystem implementation
987987
//===-----------------------------------------------------------------------===/
988988

989+
RedirectingFileSystem::RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> FS)
990+
: ExternalFS(std::move(FS)) {
991+
if (ExternalFS)
992+
if (auto ExternalWorkingDirectory =
993+
ExternalFS->getCurrentWorkingDirectory()) {
994+
WorkingDirectory = *ExternalWorkingDirectory;
995+
ExternalFSValidWD = true;
996+
}
997+
}
998+
989999
// FIXME: reuse implementation common with OverlayFSDirIterImpl as these
9901000
// iterators are conceptually similar.
9911001
class llvm::vfs::VFSFromYamlDirIterImpl
@@ -1032,12 +1042,27 @@ class llvm::vfs::VFSFromYamlDirIterImpl
10321042

10331043
llvm::ErrorOr<std::string>
10341044
RedirectingFileSystem::getCurrentWorkingDirectory() const {
1035-
return ExternalFS->getCurrentWorkingDirectory();
1045+
return WorkingDirectory;
10361046
}
10371047

10381048
std::error_code
10391049
RedirectingFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
1040-
return ExternalFS->setCurrentWorkingDirectory(Path);
1050+
// Don't change the working directory if the path doesn't exist.
1051+
if (!exists(Path))
1052+
return errc::no_such_file_or_directory;
1053+
1054+
// Always change the external FS but ignore its result.
1055+
if (ExternalFS) {
1056+
auto EC = ExternalFS->setCurrentWorkingDirectory(Path);
1057+
ExternalFSValidWD = !static_cast<bool>(EC);
1058+
}
1059+
1060+
SmallString<128> AbsolutePath;
1061+
Path.toVector(AbsolutePath);
1062+
if (std::error_code EC = makeAbsolute(AbsolutePath))
1063+
return EC;
1064+
WorkingDirectory = AbsolutePath.str();
1065+
return {};
10411066
}
10421067

10431068
std::error_code RedirectingFileSystem::isLocal(const Twine &Path,
@@ -1050,7 +1075,7 @@ directory_iterator RedirectingFileSystem::dir_begin(const Twine &Dir,
10501075
ErrorOr<RedirectingFileSystem::Entry *> E = lookupPath(Dir);
10511076
if (!E) {
10521077
EC = E.getError();
1053-
if (IsFallthrough && EC == errc::no_such_file_or_directory)
1078+
if (shouldUseExternalFS() && EC == errc::no_such_file_or_directory)
10541079
return ExternalFS->dir_begin(Dir, EC);
10551080
return {};
10561081
}
@@ -1068,7 +1093,7 @@ directory_iterator RedirectingFileSystem::dir_begin(const Twine &Dir,
10681093
auto *D = cast<RedirectingFileSystem::RedirectingDirectoryEntry>(*E);
10691094
return directory_iterator(std::make_shared<VFSFromYamlDirIterImpl>(
10701095
Dir, D->contents_begin(), D->contents_end(),
1071-
/*IterateExternalFS=*/IsFallthrough, *ExternalFS, EC));
1096+
/*IterateExternalFS=*/shouldUseExternalFS(), *ExternalFS, EC));
10721097
}
10731098

10741099
void RedirectingFileSystem::setExternalContentsPrefixDir(StringRef PrefixDir) {
@@ -1218,7 +1243,7 @@ class llvm::vfs::RedirectingFileSystemParser {
12181243
}
12191244

12201245
auto *DE =
1221-
dyn_cast<RedirectingFileSystem::RedirectingDirectoryEntry>(ParentEntry);
1246+
cast<RedirectingFileSystem::RedirectingDirectoryEntry>(ParentEntry);
12221247
DE->addContent(std::move(E));
12231248
return DE->getLastContent();
12241249
}
@@ -1229,9 +1254,7 @@ class llvm::vfs::RedirectingFileSystemParser {
12291254
StringRef Name = SrcE->getName();
12301255
switch (SrcE->getKind()) {
12311256
case RedirectingFileSystem::EK_Directory: {
1232-
auto *DE =
1233-
dyn_cast<RedirectingFileSystem::RedirectingDirectoryEntry>(SrcE);
1234-
assert(DE && "Must be a directory");
1257+
auto *DE = cast<RedirectingFileSystem::RedirectingDirectoryEntry>(SrcE);
12351258
// Empty directories could be present in the YAML as a way to
12361259
// describe a file for a current directory after some of its subdir
12371260
// is parsed. This only leads to redundant walks, ignore it.
@@ -1243,11 +1266,10 @@ class llvm::vfs::RedirectingFileSystemParser {
12431266
break;
12441267
}
12451268
case RedirectingFileSystem::EK_File: {
1246-
auto *FE = dyn_cast<RedirectingFileSystem::RedirectingFileEntry>(SrcE);
1247-
assert(FE && "Must be a file");
12481269
assert(NewParentE && "Parent entry must exist");
1249-
auto *DE = dyn_cast<RedirectingFileSystem::RedirectingDirectoryEntry>(
1250-
NewParentE);
1270+
auto *FE = cast<RedirectingFileSystem::RedirectingFileEntry>(SrcE);
1271+
auto *DE =
1272+
cast<RedirectingFileSystem::RedirectingDirectoryEntry>(NewParentE);
12511273
DE->addContent(
12521274
llvm::make_unique<RedirectingFileSystem::RedirectingFileEntry>(
12531275
Name, FE->getExternalContentsPath(), FE->getUseName()));
@@ -1570,7 +1592,7 @@ RedirectingFileSystem::create(std::unique_ptr<MemoryBuffer> Buffer,
15701592
RedirectingFileSystemParser P(Stream);
15711593

15721594
std::unique_ptr<RedirectingFileSystem> FS(
1573-
new RedirectingFileSystem(std::move(ExternalFS)));
1595+
new RedirectingFileSystem(ExternalFS));
15741596

15751597
if (!YAMLFilePath.empty()) {
15761598
// Use the YAML path from -ivfsoverlay to compute the dir to be prefixed
@@ -1699,7 +1721,7 @@ ErrorOr<Status> RedirectingFileSystem::status(const Twine &Path,
16991721
ErrorOr<Status> RedirectingFileSystem::status(const Twine &Path) {
17001722
ErrorOr<RedirectingFileSystem::Entry *> Result = lookupPath(Path);
17011723
if (!Result) {
1702-
if (IsFallthrough &&
1724+
if (shouldUseExternalFS() &&
17031725
Result.getError() == llvm::errc::no_such_file_or_directory) {
17041726
return ExternalFS->status(Path);
17051727
}
@@ -1737,7 +1759,7 @@ ErrorOr<std::unique_ptr<File>>
17371759
RedirectingFileSystem::openFileForRead(const Twine &Path) {
17381760
ErrorOr<RedirectingFileSystem::Entry *> E = lookupPath(Path);
17391761
if (!E) {
1740-
if (IsFallthrough &&
1762+
if (shouldUseExternalFS() &&
17411763
E.getError() == llvm::errc::no_such_file_or_directory) {
17421764
return ExternalFS->openFileForRead(Path);
17431765
}
@@ -1768,7 +1790,7 @@ RedirectingFileSystem::getRealPath(const Twine &Path,
17681790
SmallVectorImpl<char> &Output) const {
17691791
ErrorOr<RedirectingFileSystem::Entry *> Result = lookupPath(Path);
17701792
if (!Result) {
1771-
if (IsFallthrough &&
1793+
if (shouldUseExternalFS() &&
17721794
Result.getError() == llvm::errc::no_such_file_or_directory) {
17731795
return ExternalFS->getRealPath(Path, Output);
17741796
}
@@ -1781,8 +1803,8 @@ RedirectingFileSystem::getRealPath(const Twine &Path,
17811803
}
17821804
// Even if there is a directory entry, fall back to ExternalFS if allowed,
17831805
// because directories don't have a single external contents path.
1784-
return IsFallthrough ? ExternalFS->getRealPath(Path, Output)
1785-
: llvm::errc::invalid_argument;
1806+
return shouldUseExternalFS() ? ExternalFS->getRealPath(Path, Output)
1807+
: llvm::errc::invalid_argument;
17861808
}
17871809

17881810
IntrusiveRefCntPtr<FileSystem>

llvm/unittests/Support/Path.cpp

+13-4
Original file line numberDiff line numberDiff line change
@@ -185,10 +185,19 @@ TEST(Support, Path) {
185185
path::native(*i, temp_store);
186186
}
187187

188-
SmallString<32> Relative("foo.cpp");
189-
sys::fs::make_absolute("/root", Relative);
190-
Relative[5] = '/'; // Fix up windows paths.
191-
ASSERT_EQ("/root/foo.cpp", Relative);
188+
{
189+
SmallString<32> Relative("foo.cpp");
190+
sys::fs::make_absolute("/root", Relative);
191+
Relative[5] = '/'; // Fix up windows paths.
192+
ASSERT_EQ("/root/foo.cpp", Relative);
193+
}
194+
195+
{
196+
SmallString<32> Relative("foo.cpp");
197+
sys::fs::make_absolute("//root", Relative);
198+
Relative[6] = '/'; // Fix up windows paths.
199+
ASSERT_EQ("//root/foo.cpp", Relative);
200+
}
192201
}
193202

194203
TEST(Support, FilenameParent) {

0 commit comments

Comments
 (0)