Skip to content
Merged
26 changes: 22 additions & 4 deletions llvm/include/llvm/Support/VirtualFileSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -343,15 +343,24 @@ class OverlayFileSystem : public FileSystem {

using iterator = FileSystemList::reverse_iterator;
using const_iterator = FileSystemList::const_reverse_iterator;
using reverse_iterator = FileSystemList::iterator;
using const_reverse_iterator = FileSystemList::const_iterator;

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

/// Get an iterator pointing one-past the least recently added file
/// system.
/// Get an iterator pointing one-past the least recently added file system.
iterator overlays_end() { return FSList.rend(); }
const_iterator overlays_end() const { return FSList.rend(); }

/// Get an iterator pointing to the least recently added file system.
reverse_iterator overlays_rbegin() { return FSList.begin(); }
const_reverse_iterator overlays_rbegin() const { return FSList.begin(); }

/// Get an iterator pointing one-past the most recently added file system.
reverse_iterator overlays_rend() { return FSList.end(); }
const_reverse_iterator overlays_rend() const { return FSList.end(); }
};

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

bool shouldUseExternalFS() const {
return ExternalFSValidWD && IsFallthrough;
}

/// The root(s) of the virtual file system.
std::vector<std::unique_ptr<Entry>> Roots;

/// The current working directory of the file system.
std::string WorkingDirectory;

/// Whether the current working directory is valid for the external FS.
bool ExternalFSValidWD = false;

/// The file system to use for external references.
IntrusiveRefCntPtr<FileSystem> ExternalFS;

Expand Down Expand Up @@ -680,8 +699,7 @@ class RedirectingFileSystem : public vfs::FileSystem {
true;
#endif

RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> ExternalFS)
: ExternalFS(std::move(ExternalFS)) {}
RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> ExternalFS);

/// Looks up the path <tt>[Start, End)</tt> in \p From, possibly
/// recursing into the contents of \p From if it is a directory.
Expand Down
6 changes: 3 additions & 3 deletions llvm/lib/Support/Path.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -855,11 +855,11 @@ void make_absolute(const Twine &current_directory,
StringRef p(path.data(), path.size());

bool rootDirectory = path::has_root_directory(p);
bool rootName =
(real_style(Style::native) != Style::windows) || path::has_root_name(p);
bool rootName = path::has_root_name(p);

// Already absolute.
if (rootName && rootDirectory)
if ((rootName || real_style(Style::native) != Style::windows) &&
rootDirectory)
return;

// All of the following conditions will need the current directory.
Expand Down
58 changes: 40 additions & 18 deletions llvm/lib/Support/VirtualFileSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -986,6 +986,16 @@ std::error_code InMemoryFileSystem::isLocal(const Twine &Path, bool &Result) {
// RedirectingFileSystem implementation
//===-----------------------------------------------------------------------===/

RedirectingFileSystem::RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> FS)
: ExternalFS(std::move(FS)) {
if (ExternalFS)
if (auto ExternalWorkingDirectory =
ExternalFS->getCurrentWorkingDirectory()) {
WorkingDirectory = *ExternalWorkingDirectory;
ExternalFSValidWD = true;
}
}

// FIXME: reuse implementation common with OverlayFSDirIterImpl as these
// iterators are conceptually similar.
class llvm::vfs::VFSFromYamlDirIterImpl
Expand Down Expand Up @@ -1032,12 +1042,27 @@ class llvm::vfs::VFSFromYamlDirIterImpl

llvm::ErrorOr<std::string>
RedirectingFileSystem::getCurrentWorkingDirectory() const {
return ExternalFS->getCurrentWorkingDirectory();
return WorkingDirectory;
}

std::error_code
RedirectingFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
return ExternalFS->setCurrentWorkingDirectory(Path);
// Don't change the working directory if the path doesn't exist.
if (!exists(Path))
return errc::no_such_file_or_directory;

// Always change the external FS but ignore its result.
if (ExternalFS) {
auto EC = ExternalFS->setCurrentWorkingDirectory(Path);
ExternalFSValidWD = !static_cast<bool>(EC);
}

SmallString<128> AbsolutePath;
Path.toVector(AbsolutePath);
if (std::error_code EC = makeAbsolute(AbsolutePath))
return EC;
WorkingDirectory = AbsolutePath.str();
return {};
}

std::error_code RedirectingFileSystem::isLocal(const Twine &Path,
Expand All @@ -1050,7 +1075,7 @@ directory_iterator RedirectingFileSystem::dir_begin(const Twine &Dir,
ErrorOr<RedirectingFileSystem::Entry *> E = lookupPath(Dir);
if (!E) {
EC = E.getError();
if (IsFallthrough && EC == errc::no_such_file_or_directory)
if (shouldUseExternalFS() && EC == errc::no_such_file_or_directory)
return ExternalFS->dir_begin(Dir, EC);
return {};
}
Expand All @@ -1068,7 +1093,7 @@ directory_iterator RedirectingFileSystem::dir_begin(const Twine &Dir,
auto *D = cast<RedirectingFileSystem::RedirectingDirectoryEntry>(*E);
return directory_iterator(std::make_shared<VFSFromYamlDirIterImpl>(
Dir, D->contents_begin(), D->contents_end(),
/*IterateExternalFS=*/IsFallthrough, *ExternalFS, EC));
/*IterateExternalFS=*/shouldUseExternalFS(), *ExternalFS, EC));
}

void RedirectingFileSystem::setExternalContentsPrefixDir(StringRef PrefixDir) {
Expand Down Expand Up @@ -1218,7 +1243,7 @@ class llvm::vfs::RedirectingFileSystemParser {
}

auto *DE =
dyn_cast<RedirectingFileSystem::RedirectingDirectoryEntry>(ParentEntry);
cast<RedirectingFileSystem::RedirectingDirectoryEntry>(ParentEntry);
DE->addContent(std::move(E));
return DE->getLastContent();
}
Expand All @@ -1229,9 +1254,7 @@ class llvm::vfs::RedirectingFileSystemParser {
StringRef Name = SrcE->getName();
switch (SrcE->getKind()) {
case RedirectingFileSystem::EK_Directory: {
auto *DE =
dyn_cast<RedirectingFileSystem::RedirectingDirectoryEntry>(SrcE);
assert(DE && "Must be a directory");
auto *DE = cast<RedirectingFileSystem::RedirectingDirectoryEntry>(SrcE);
// Empty directories could be present in the YAML as a way to
// describe a file for a current directory after some of its subdir
// is parsed. This only leads to redundant walks, ignore it.
Expand All @@ -1243,11 +1266,10 @@ class llvm::vfs::RedirectingFileSystemParser {
break;
}
case RedirectingFileSystem::EK_File: {
auto *FE = dyn_cast<RedirectingFileSystem::RedirectingFileEntry>(SrcE);
assert(FE && "Must be a file");
assert(NewParentE && "Parent entry must exist");
auto *DE = dyn_cast<RedirectingFileSystem::RedirectingDirectoryEntry>(
NewParentE);
auto *FE = cast<RedirectingFileSystem::RedirectingFileEntry>(SrcE);
auto *DE =
cast<RedirectingFileSystem::RedirectingDirectoryEntry>(NewParentE);
DE->addContent(
llvm::make_unique<RedirectingFileSystem::RedirectingFileEntry>(
Name, FE->getExternalContentsPath(), FE->getUseName()));
Expand Down Expand Up @@ -1570,7 +1592,7 @@ RedirectingFileSystem::create(std::unique_ptr<MemoryBuffer> Buffer,
RedirectingFileSystemParser P(Stream);

std::unique_ptr<RedirectingFileSystem> FS(
new RedirectingFileSystem(std::move(ExternalFS)));
new RedirectingFileSystem(ExternalFS));

if (!YAMLFilePath.empty()) {
// Use the YAML path from -ivfsoverlay to compute the dir to be prefixed
Expand Down Expand Up @@ -1699,7 +1721,7 @@ ErrorOr<Status> RedirectingFileSystem::status(const Twine &Path,
ErrorOr<Status> RedirectingFileSystem::status(const Twine &Path) {
ErrorOr<RedirectingFileSystem::Entry *> Result = lookupPath(Path);
if (!Result) {
if (IsFallthrough &&
if (shouldUseExternalFS() &&
Result.getError() == llvm::errc::no_such_file_or_directory) {
return ExternalFS->status(Path);
}
Expand Down Expand Up @@ -1737,7 +1759,7 @@ ErrorOr<std::unique_ptr<File>>
RedirectingFileSystem::openFileForRead(const Twine &Path) {
ErrorOr<RedirectingFileSystem::Entry *> E = lookupPath(Path);
if (!E) {
if (IsFallthrough &&
if (shouldUseExternalFS() &&
E.getError() == llvm::errc::no_such_file_or_directory) {
return ExternalFS->openFileForRead(Path);
}
Expand Down Expand Up @@ -1768,7 +1790,7 @@ RedirectingFileSystem::getRealPath(const Twine &Path,
SmallVectorImpl<char> &Output) const {
ErrorOr<RedirectingFileSystem::Entry *> Result = lookupPath(Path);
if (!Result) {
if (IsFallthrough &&
if (shouldUseExternalFS() &&
Result.getError() == llvm::errc::no_such_file_or_directory) {
return ExternalFS->getRealPath(Path, Output);
}
Expand All @@ -1781,8 +1803,8 @@ RedirectingFileSystem::getRealPath(const Twine &Path,
}
// Even if there is a directory entry, fall back to ExternalFS if allowed,
// because directories don't have a single external contents path.
return IsFallthrough ? ExternalFS->getRealPath(Path, Output)
: llvm::errc::invalid_argument;
return shouldUseExternalFS() ? ExternalFS->getRealPath(Path, Output)
: llvm::errc::invalid_argument;
}

IntrusiveRefCntPtr<FileSystem>
Expand Down
17 changes: 13 additions & 4 deletions llvm/unittests/Support/Path.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,10 +185,19 @@ TEST(Support, Path) {
path::native(*i, temp_store);
}

SmallString<32> Relative("foo.cpp");
sys::fs::make_absolute("/root", Relative);
Relative[5] = '/'; // Fix up windows paths.
ASSERT_EQ("/root/foo.cpp", Relative);
{
SmallString<32> Relative("foo.cpp");
sys::fs::make_absolute("/root", Relative);
Relative[5] = '/'; // Fix up windows paths.
ASSERT_EQ("/root/foo.cpp", Relative);
}

{
SmallString<32> Relative("foo.cpp");
sys::fs::make_absolute("//root", Relative);
Relative[6] = '/'; // Fix up windows paths.
ASSERT_EQ("//root/foo.cpp", Relative);
}
}

TEST(Support, FilenameParent) {
Expand Down
Loading