diff options
Diffstat (limited to 'llvm/lib/Support/VirtualFileSystem.cpp')
-rw-r--r-- | llvm/lib/Support/VirtualFileSystem.cpp | 175 |
1 files changed, 133 insertions, 42 deletions
diff --git a/llvm/lib/Support/VirtualFileSystem.cpp b/llvm/lib/Support/VirtualFileSystem.cpp index 15bb54e61817..9bf0384b5f1b 100644 --- a/llvm/lib/Support/VirtualFileSystem.cpp +++ b/llvm/lib/Support/VirtualFileSystem.cpp @@ -32,6 +32,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/FileSystem/UniqueID.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" @@ -193,6 +194,7 @@ public: bool RequiresNullTerminator, bool IsVolatile) override; std::error_code close() override; + void setPath(const Twine &Path) override; }; } // namespace @@ -228,6 +230,12 @@ std::error_code RealFile::close() { return EC; } +void RealFile::setPath(const Twine &Path) { + RealName = Path.str(); + if (auto Status = status()) + S = Status.get().copyWithNewName(Status.get(), Path); +} + namespace { /// A file system according to your operating system. @@ -442,7 +450,7 @@ std::error_code OverlayFileSystem::isLocal(const Twine &Path, bool &Result) { std::error_code OverlayFileSystem::getRealPath(const Twine &Path, SmallVectorImpl<char> &Output) const { - for (auto &FS : FSList) + for (const auto &FS : FSList) if (FS->exists(Path)) return FS->getRealPath(Path, Output); return errc::no_such_file_or_directory; @@ -638,6 +646,8 @@ public: } std::error_code close() override { return {}; } + + void setPath(const Twine &Path) override { RequestedName = Path.str(); } }; } // namespace @@ -655,6 +665,9 @@ public: Status getStatus(const Twine &RequestedName) const { return Status::copyWithNewName(Stat, RequestedName); } + + UniqueID getUniqueID() const { return Stat.getUniqueID(); } + InMemoryNode *getChild(StringRef Name) { auto I = Entries.find(Name); if (I != Entries.end()) @@ -698,10 +711,28 @@ Status getNodeStatus(const InMemoryNode *Node, const Twine &RequestedName) { } // namespace } // namespace detail +// The UniqueID of in-memory files is derived from path and content. +// This avoids difficulties in creating exactly equivalent in-memory FSes, +// as often needed in multithreaded programs. +static sys::fs::UniqueID getUniqueID(hash_code Hash) { + return sys::fs::UniqueID(std::numeric_limits<uint64_t>::max(), + uint64_t(size_t(Hash))); +} +static sys::fs::UniqueID getFileID(sys::fs::UniqueID Parent, + llvm::StringRef Name, + llvm::StringRef Contents) { + return getUniqueID(llvm::hash_combine(Parent.getFile(), Name, Contents)); +} +static sys::fs::UniqueID getDirectoryID(sys::fs::UniqueID Parent, + llvm::StringRef Name) { + return getUniqueID(llvm::hash_combine(Parent.getFile(), Name)); +} + InMemoryFileSystem::InMemoryFileSystem(bool UseNormalizedPaths) : Root(new detail::InMemoryDirectory( - Status("", getNextVirtualUniqueID(), llvm::sys::TimePoint<>(), 0, 0, - 0, llvm::sys::fs::file_type::directory_file, + Status("", getDirectoryID(llvm::sys::fs::UniqueID(), ""), + llvm::sys::TimePoint<>(), 0, 0, 0, + llvm::sys::fs::file_type::directory_file, llvm::sys::fs::perms::all_all))), UseNormalizedPaths(UseNormalizedPaths) {} @@ -754,10 +785,14 @@ bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime, Child.reset(new detail::InMemoryHardLink(P.str(), *HardLinkTarget)); else { // Create a new file or directory. - Status Stat(P.str(), getNextVirtualUniqueID(), - llvm::sys::toTimePoint(ModificationTime), ResolvedUser, - ResolvedGroup, Buffer->getBufferSize(), ResolvedType, - ResolvedPerms); + Status Stat( + P.str(), + (ResolvedType == sys::fs::file_type::directory_file) + ? getDirectoryID(Dir->getUniqueID(), Name) + : getFileID(Dir->getUniqueID(), Name, Buffer->getBuffer()), + llvm::sys::toTimePoint(ModificationTime), ResolvedUser, + ResolvedGroup, Buffer->getBufferSize(), ResolvedType, + ResolvedPerms); if (ResolvedType == sys::fs::file_type::directory_file) { Child.reset(new detail::InMemoryDirectory(std::move(Stat))); } else { @@ -772,9 +807,9 @@ bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime, // Create a new directory. Use the path up to here. Status Stat( StringRef(Path.str().begin(), Name.end() - Path.str().begin()), - getNextVirtualUniqueID(), llvm::sys::toTimePoint(ModificationTime), - ResolvedUser, ResolvedGroup, 0, sys::fs::file_type::directory_file, - NewDirectoryPerms); + getDirectoryID(Dir->getUniqueID(), Name), + llvm::sys::toTimePoint(ModificationTime), ResolvedUser, ResolvedGroup, + 0, sys::fs::file_type::directory_file, NewDirectoryPerms); Dir = cast<detail::InMemoryDirectory>(Dir->addChild( Name, std::make_unique<detail::InMemoryDirectory>(std::move(Stat)))); continue; @@ -1015,9 +1050,10 @@ static llvm::sys::path::Style getExistingStyle(llvm::StringRef Path) { // Detect the path style in use by checking the first separator. llvm::sys::path::Style style = llvm::sys::path::Style::native; const size_t n = Path.find_first_of("/\\"); + // Can't distinguish between posix and windows_slash here. if (n != static_cast<size_t>(-1)) style = (Path[n] == '/') ? llvm::sys::path::Style::posix - : llvm::sys::path::Style::windows; + : llvm::sys::path::Style::windows_backslash; return style; } @@ -1091,6 +1127,7 @@ public: } }; +namespace { /// Directory iterator implementation for \c RedirectingFileSystem's /// directory remap entries that maps the paths reported by the external /// file system's directory iterator back to the virtual directory's path. @@ -1129,6 +1166,7 @@ public: return EC; } }; +} // namespace llvm::ErrorOr<std::string> RedirectingFileSystem::getCurrentWorkingDirectory() const { @@ -1161,8 +1199,10 @@ std::error_code RedirectingFileSystem::isLocal(const Twine &Path_, } std::error_code RedirectingFileSystem::makeAbsolute(SmallVectorImpl<char> &Path) const { + // is_absolute(..., Style::windows_*) accepts paths with both slash types. if (llvm::sys::path::is_absolute(Path, llvm::sys::path::Style::posix) || - llvm::sys::path::is_absolute(Path, llvm::sys::path::Style::windows)) + llvm::sys::path::is_absolute(Path, + llvm::sys::path::Style::windows_backslash)) return {}; auto WorkingDir = getCurrentWorkingDirectory(); @@ -1173,9 +1213,15 @@ std::error_code RedirectingFileSystem::makeAbsolute(SmallVectorImpl<char> &Path) // is native and there is no way to override that. Since we know WorkingDir // is absolute, we can use it to determine which style we actually have and // append Path ourselves. - sys::path::Style style = sys::path::Style::windows; + sys::path::Style style = sys::path::Style::windows_backslash; if (sys::path::is_absolute(WorkingDir.get(), sys::path::Style::posix)) { style = sys::path::Style::posix; + } else { + // Distinguish between windows_backslash and windows_slash; getExistingStyle + // returns posix for a path with windows_slash. + if (getExistingStyle(WorkingDir.get()) != + sys::path::Style::windows_backslash) + style = sys::path::Style::windows_slash; } std::string Result = WorkingDir.get(); @@ -1207,7 +1253,7 @@ directory_iterator RedirectingFileSystem::dir_begin(const Twine &Dir, } // Use status to make sure the path exists and refers to a directory. - ErrorOr<Status> S = status(Path, *Result); + ErrorOr<Status> S = status(Path, Dir, *Result); if (!S) { if (shouldFallBackToExternalFS(S.getError(), Result->E)) return ExternalFS->dir_begin(Dir, EC); @@ -1593,8 +1639,9 @@ private: // which style we have, and use it consistently. if (sys::path::is_absolute(Name, sys::path::Style::posix)) { path_style = sys::path::Style::posix; - } else if (sys::path::is_absolute(Name, sys::path::Style::windows)) { - path_style = sys::path::Style::windows; + } else if (sys::path::is_absolute(Name, + sys::path::Style::windows_backslash)) { + path_style = sys::path::Style::windows_backslash; } else { assert(NameValueNode && "Name presence should be checked earlier"); error(NameValueNode, @@ -1933,47 +1980,68 @@ RedirectingFileSystem::lookupPathImpl( return make_error_code(llvm::errc::no_such_file_or_directory); } -static Status getRedirectedFileStatus(const Twine &Path, bool UseExternalNames, +static Status getRedirectedFileStatus(const Twine &OriginalPath, + bool UseExternalNames, Status ExternalStatus) { Status S = ExternalStatus; if (!UseExternalNames) - S = Status::copyWithNewName(S, Path); + S = Status::copyWithNewName(S, OriginalPath); S.IsVFSMapped = true; return S; } ErrorOr<Status> RedirectingFileSystem::status( - const Twine &Path, const RedirectingFileSystem::LookupResult &Result) { + const Twine &CanonicalPath, const Twine &OriginalPath, + const RedirectingFileSystem::LookupResult &Result) { if (Optional<StringRef> ExtRedirect = Result.getExternalRedirect()) { - ErrorOr<Status> S = ExternalFS->status(*ExtRedirect); + SmallString<256> CanonicalRemappedPath((*ExtRedirect).str()); + if (std::error_code EC = makeCanonical(CanonicalRemappedPath)) + return EC; + + ErrorOr<Status> S = ExternalFS->status(CanonicalRemappedPath); if (!S) return S; + S = Status::copyWithNewName(*S, *ExtRedirect); auto *RE = cast<RedirectingFileSystem::RemapEntry>(Result.E); - return getRedirectedFileStatus(Path, RE->useExternalName(UseExternalNames), - *S); + return getRedirectedFileStatus(OriginalPath, + RE->useExternalName(UseExternalNames), *S); } auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(Result.E); - return Status::copyWithNewName(DE->getStatus(), Path); + return Status::copyWithNewName(DE->getStatus(), CanonicalPath); } -ErrorOr<Status> RedirectingFileSystem::status(const Twine &Path_) { - SmallString<256> Path; - Path_.toVector(Path); +ErrorOr<Status> +RedirectingFileSystem::getExternalStatus(const Twine &CanonicalPath, + const Twine &OriginalPath) const { + if (auto Result = ExternalFS->status(CanonicalPath)) { + return Result.get().copyWithNewName(Result.get(), OriginalPath); + } else { + return Result.getError(); + } +} - if (std::error_code EC = makeCanonical(Path)) +ErrorOr<Status> RedirectingFileSystem::status(const Twine &OriginalPath) { + SmallString<256> CanonicalPath; + OriginalPath.toVector(CanonicalPath); + + if (std::error_code EC = makeCanonical(CanonicalPath)) return EC; - ErrorOr<RedirectingFileSystem::LookupResult> Result = lookupPath(Path); + ErrorOr<RedirectingFileSystem::LookupResult> Result = + lookupPath(CanonicalPath); if (!Result) { - if (shouldFallBackToExternalFS(Result.getError())) - return ExternalFS->status(Path); + if (shouldFallBackToExternalFS(Result.getError())) { + return getExternalStatus(CanonicalPath, OriginalPath); + } return Result.getError(); } - ErrorOr<Status> S = status(Path, *Result); - if (!S && shouldFallBackToExternalFS(S.getError(), Result->E)) - S = ExternalFS->status(Path); + ErrorOr<Status> S = status(CanonicalPath, OriginalPath, *Result); + if (!S && shouldFallBackToExternalFS(S.getError(), Result->E)) { + return getExternalStatus(CanonicalPath, OriginalPath); + } + return S; } @@ -1998,22 +2066,39 @@ public: } std::error_code close() override { return InnerFile->close(); } + + void setPath(const Twine &Path) override { S = S.copyWithNewName(S, Path); } }; } // namespace ErrorOr<std::unique_ptr<File>> -RedirectingFileSystem::openFileForRead(const Twine &Path_) { - SmallString<256> Path; - Path_.toVector(Path); +File::getWithPath(ErrorOr<std::unique_ptr<File>> Result, const Twine &P) { + if (!Result) + return Result; - if (std::error_code EC = makeCanonical(Path)) + ErrorOr<std::unique_ptr<File>> F = std::move(*Result); + auto Name = F->get()->getName(); + if (Name && Name.get() != P.str()) + F->get()->setPath(P); + return F; +} + +ErrorOr<std::unique_ptr<File>> +RedirectingFileSystem::openFileForRead(const Twine &OriginalPath) { + SmallString<256> CanonicalPath; + OriginalPath.toVector(CanonicalPath); + + if (std::error_code EC = makeCanonical(CanonicalPath)) return EC; - ErrorOr<RedirectingFileSystem::LookupResult> Result = lookupPath(Path); + ErrorOr<RedirectingFileSystem::LookupResult> Result = + lookupPath(CanonicalPath); if (!Result) { if (shouldFallBackToExternalFS(Result.getError())) - return ExternalFS->openFileForRead(Path); + return File::getWithPath(ExternalFS->openFileForRead(CanonicalPath), + OriginalPath); + return Result.getError(); } @@ -2021,12 +2106,18 @@ RedirectingFileSystem::openFileForRead(const Twine &Path_) { return make_error_code(llvm::errc::invalid_argument); StringRef ExtRedirect = *Result->getExternalRedirect(); + SmallString<256> CanonicalRemappedPath(ExtRedirect.str()); + if (std::error_code EC = makeCanonical(CanonicalRemappedPath)) + return EC; + auto *RE = cast<RedirectingFileSystem::RemapEntry>(Result->E); - auto ExternalFile = ExternalFS->openFileForRead(ExtRedirect); + auto ExternalFile = File::getWithPath( + ExternalFS->openFileForRead(CanonicalRemappedPath), ExtRedirect); if (!ExternalFile) { if (shouldFallBackToExternalFS(ExternalFile.getError(), Result->E)) - return ExternalFS->openFileForRead(Path); + return File::getWithPath(ExternalFS->openFileForRead(CanonicalPath), + OriginalPath); return ExternalFile; } @@ -2036,7 +2127,7 @@ RedirectingFileSystem::openFileForRead(const Twine &Path_) { // FIXME: Update the status with the name and VFSMapped. Status S = getRedirectedFileStatus( - Path, RE->useExternalName(UseExternalNames), *ExternalStatus); + OriginalPath, RE->useExternalName(UseExternalNames), *ExternalStatus); return std::unique_ptr<File>( std::make_unique<FileWithFixedStatus>(std::move(*ExternalFile), S)); } |