21#include "llvm/ADT/STLExtras.h"
22#include "llvm/ADT/SmallString.h"
23#include "llvm/ADT/Statistic.h"
24#include "llvm/Config/llvm-config.h"
25#include "llvm/Support/FileSystem.h"
26#include "llvm/Support/MemoryBuffer.h"
27#include "llvm/Support/Path.h"
28#include "llvm/Support/raw_ostream.h"
40#define DEBUG_TYPE "file-search"
48 : FS(
std::move(FS)), FileSystemOpts(FSO), SeenDirEntries(64),
49 SeenFileEntries(64), NextFileUID(0) {
53 this->FS = llvm::vfs::getRealFileSystem();
59 assert(statCache &&
"No stat cache provided?");
60 StatCache = std::move(statCache);
71 return llvm::errorCodeToError(
75 return llvm::errorCodeToError(
make_error_code(std::errc::is_a_directory));
77 StringRef DirName = llvm::sys::path::parent_path(
Filename);
85DirectoryEntry *&FileManager::getRealDirEntry(
const llvm::vfs::Status &Status) {
86 assert(Status.isDirectory() &&
"The directory should exist!");
103void FileManager::addAncestorsAsVirtualDirs(StringRef
Path) {
104 StringRef DirName = llvm::sys::path::parent_path(
Path);
108 auto &NamedDirEnt = *SeenDirEntries.insert(
109 {DirName, std::errc::no_such_file_or_directory}).first;
115 if (NamedDirEnt.second)
119 llvm::vfs::Status Status;
121 getStatValue(DirName, Status,
false,
nullptr );
126 NamedDirEnt.second = *UDE;
127 VirtualDirectoryEntries.push_back(UDE);
131 NamedDirEnt.second = *UDE;
135 addAncestorsAsVirtualDirs(DirName);
143 if (DirName.size() > 1 &&
144 DirName != llvm::sys::path::root_path(DirName) &&
145 llvm::sys::path::is_separator(DirName.back()))
146 DirName = DirName.substr(0, DirName.size()-1);
147 std::optional<std::string> DirNameStr;
148 if (is_style_windows(llvm::sys::path::Style::native)) {
151 if (DirName.size() > 1 && DirName.back() ==
':' &&
152 DirName.equals_insensitive(llvm::sys::path::root_name(DirName))) {
153 DirNameStr = DirName.str() +
'.';
154 DirName = *DirNameStr;
162 auto SeenDirInsertResult =
163 SeenDirEntries.insert({DirName, std::errc::no_such_file_or_directory});
164 if (!SeenDirInsertResult.second) {
165 if (SeenDirInsertResult.first->second)
167 return llvm::errorCodeToError(SeenDirInsertResult.first->second.getError());
172 auto &NamedDirEnt = *SeenDirInsertResult.first;
173 assert(!NamedDirEnt.second &&
"should be newly-created");
177 StringRef InterndDirName = NamedDirEnt.first();
180 llvm::vfs::Status Status;
181 auto statError = getStatValue(InterndDirName, Status,
false,
186 NamedDirEnt.second = statError;
188 SeenDirEntries.erase(DirName);
189 return llvm::errorCodeToError(statError);
194 NamedDirEnt.second = *UDE;
199llvm::ErrorOr<const DirectoryEntry *>
200FileManager::getDirectory(StringRef DirName,
bool CacheFailure) {
203 return &
Result->getDirEntry();
204 return llvm::errorToErrorCode(
Result.takeError());
207llvm::ErrorOr<const FileEntry *>
208FileManager::getFile(StringRef
Filename,
bool openFile,
bool CacheFailure) {
211 return &
Result->getFileEntry();
212 return llvm::errorToErrorCode(
Result.takeError());
222 auto SeenFileInsertResult =
223 SeenFileEntries.insert({
Filename, std::errc::no_such_file_or_directory});
224 if (!SeenFileInsertResult.second) {
225 if (!SeenFileInsertResult.first->second)
226 return llvm::errorCodeToError(
227 SeenFileInsertResult.first->second.getError());
232 ++NumFileCacheMisses;
233 auto *NamedFileEnt = &*SeenFileInsertResult.first;
234 assert(!NamedFileEnt->second &&
"should be newly-created");
238 StringRef InterndFileName = NamedFileEnt->first();
247 std::error_code Err = errorToErrorCode(DirInfoOrErr.takeError());
249 NamedFileEnt->second = Err;
253 return llvm::errorCodeToError(Err);
261 std::unique_ptr<llvm::vfs::File> F;
262 llvm::vfs::Status Status;
263 auto statError = getStatValue(InterndFileName, Status,
true,
264 openFile ? &F :
nullptr, IsText);
268 NamedFileEnt->second = statError;
272 return llvm::errorCodeToError(statError);
275 assert((openFile || !F) &&
"undesired open file");
279 FileEntry *&UFE = UniqueRealFiles[Status.getUniqueID()];
280 bool ReusingEntry = UFE !=
nullptr;
282 UFE =
new (FilesAlloc.Allocate())
FileEntry();
284 if (!Status.ExposesExternalVFSPath || Status.getName() ==
Filename) {
327 assert(isa<FileEntry *>(Redirection.second->V) &&
328 "filename redirected to a non-canonical filename?");
329 assert(cast<FileEntry *>(Redirection.second->V) == UFE &&
330 "filename from getStatValue() refers to wrong file");
343 UFE->Size = Status.getSize();
344 UFE->ModTime = llvm::sys::toTimeT(Status.getLastModificationTime());
346 UFE->UID = NextFileUID++;
347 UFE->UniqueID = Status.getUniqueID();
348 UFE->IsNamedPipe = Status.getType() == llvm::sys::fs::file_type::fifo_file;
349 UFE->File = std::move(F);
352 if (
auto PathName = UFE->File->getName())
353 fillRealPathName(UFE, *PathName);
354 }
else if (!openFile) {
356 fillRealPathName(UFE, InterndFileName);
366 std::unique_ptr<llvm::MemoryBuffer> Content;
367 if (
auto ContentOrError = llvm::MemoryBuffer::getSTDIN())
368 Content = std::move(*ContentOrError);
370 return llvm::errorCodeToError(ContentOrError.getError());
373 Content->getBufferSize(), 0);
375 FE.Content = std::move(Content);
376 FE.IsNamedPipe =
true;
381 FS->visit([Active](llvm::vfs::FileSystem &FileSys) {
382 if (
auto *RFS = dyn_cast<llvm::vfs::RedirectingFileSystem>(&FileSys))
383 RFS->setUsageTrackingActive(Active);
388 time_t ModificationTime) {
393 time_t ModificationTime) {
397 auto &NamedFileEnt = *SeenFileEntries.insert(
398 {
Filename, std::errc::no_such_file_or_directory}).first;
399 if (NamedFileEnt.second) {
401 if (LLVM_LIKELY(isa<FileEntry *>(
Value.V)))
407 ++NumFileCacheMisses;
408 addAncestorsAsVirtualDirs(
Filename);
420 "The directory of a virtual file should already be in the cache.");
423 llvm::vfs::Status Status;
424 const char *InterndFileName = NamedFileEnt.first().data();
425 if (!getStatValue(InterndFileName, Status,
true,
nullptr)) {
426 Status = llvm::vfs::Status(
427 Status.getName(), Status.getUniqueID(),
429 Status.getUser(), Status.getGroup(),
Size,
430 Status.getType(), Status.getPermissions());
432 auto &RealFE = UniqueRealFiles[Status.getUniqueID()];
447 RealFE =
new (FilesAlloc.Allocate())
FileEntry();
448 RealFE->UniqueID = Status.getUniqueID();
449 RealFE->IsNamedPipe =
450 Status.getType() == llvm::sys::fs::file_type::fifo_file;
451 fillRealPathName(RealFE, Status.getName());
456 UFE =
new (FilesAlloc.Allocate())
FileEntry();
457 VirtualFileEntries.push_back(UFE);
463 UFE->Dir = &DirInfo->getDirEntry();
464 UFE->UID = NextFileUID++;
471 llvm::vfs::Status Status;
472 if (getStatValue(VF.
getName(), Status,
true,
nullptr))
475 if (!SeenBypassFileEntries)
476 SeenBypassFileEntries = std::make_unique<
477 llvm::StringMap<llvm::ErrorOr<FileEntryRef::MapValue>>>();
480 auto Insertion = SeenBypassFileEntries->insert(
481 {VF.
getName(), std::errc::no_such_file_or_directory});
482 if (!Insertion.second)
487 BypassFileEntries.push_back(BFE);
489 BFE->Size = Status.getSize();
491 BFE->ModTime = llvm::sys::toTimeT(Status.getLastModificationTime());
492 BFE->UID = NextFileUID++;
499 StringRef pathRef(path.data(), path.size());
502 || llvm::sys::path::is_absolute(pathRef))
506 llvm::sys::path::append(NewPath, pathRef);
514 if (!llvm::sys::path::is_absolute(StringRef(
Path.data(),
Path.size()))) {
515 FS->makeAbsolute(
Path);
529 llvm::sys::path::remove_dots(AbsPath,
true);
530 UFE->RealPathName = std::string(AbsPath);
533llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
535 bool RequiresNullTerminator,
536 std::optional<int64_t> MaybeLimit,
bool IsText) {
540 return llvm::MemoryBuffer::getMemBuffer(Entry->Content->getMemBufferRef());
542 uint64_t FileSize = Entry->
getSize();
545 FileSize = *MaybeLimit;
556 RequiresNullTerminator, isVolatile);
562 return getBufferForFileImpl(
Filename, FileSize, isVolatile,
563 RequiresNullTerminator, IsText);
566llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
567FileManager::getBufferForFileImpl(StringRef
Filename, int64_t FileSize,
568 bool isVolatile,
bool RequiresNullTerminator,
571 return FS->getBufferForFile(
Filename, FileSize, RequiresNullTerminator,
576 return FS->getBufferForFile(FilePath, FileSize, RequiresNullTerminator,
585std::error_code FileManager::getStatValue(StringRef
Path,
586 llvm::vfs::Status &Status,
588 std::unique_ptr<llvm::vfs::File> *F,
600 StatCache.get(), *FS, IsText);
605 llvm::vfs::Status &
Result) {
609 llvm::ErrorOr<llvm::vfs::Status> S = FS->status(FilePath.c_str());
613 return std::error_code();
619 UIDToFiles.resize(NextFileUID);
621 for (
const auto &Entry : SeenFileEntries) {
623 if (!Entry.getValue() || !isa<FileEntry *>(Entry.getValue()->V))
643 llvm::DenseMap<const void *, llvm::StringRef>::iterator Known =
644 CanonicalNames.find(Entry);
645 if (Known != CanonicalNames.end())
646 return Known->second;
650 StringRef CanonicalName(Name);
654 if (!FS->getRealPath(Name, RealPathBuf)) {
655 if (is_style_windows(llvm::sys::path::Style::native)) {
659 if (!FS->makeAbsolute(AbsPathBuf)) {
660 if (llvm::sys::path::root_name(RealPathBuf) ==
661 llvm::sys::path::root_name(AbsPathBuf)) {
662 CanonicalName = RealPathBuf.str().copy(CanonicalNameStorage);
667 llvm::sys::path::remove_dots(AbsPathBuf,
true);
668 CanonicalName = AbsPathBuf.str().copy(CanonicalNameStorage);
672 CanonicalName = RealPathBuf.str().copy(CanonicalNameStorage);
676 CanonicalNames.insert({Entry, CanonicalName});
677 return CanonicalName;
681 assert(&
Other !=
this &&
"Collecting stats into the same FileManager");
682 NumDirLookups +=
Other.NumDirLookups;
683 NumFileLookups +=
Other.NumFileLookups;
684 NumDirCacheMisses +=
Other.NumDirCacheMisses;
685 NumFileCacheMisses +=
Other.NumFileCacheMisses;
689 llvm::errs() <<
"\n*** File Manager Stats:\n";
690 llvm::errs() << UniqueRealFiles.size() <<
" real files found, "
691 << UniqueRealDirs.size() <<
" real dirs found.\n";
692 llvm::errs() << VirtualFileEntries.size() <<
" virtual files found, "
693 << VirtualDirectoryEntries.size() <<
" virtual dirs found.\n";
694 llvm::errs() << NumDirLookups <<
" dir lookups, "
695 << NumDirCacheMisses <<
" dir cache misses.\n";
696 llvm::errs() << NumFileLookups <<
" file lookups, "
697 << NumFileCacheMisses <<
" file cache misses.\n";
700 if (
auto *
T = dyn_cast_or_null<llvm::vfs::TracingFileSystem>(&VFS))
701 llvm::errs() <<
"\n*** Virtual File System Stats:\n"
702 <<
T->NumStatusCalls <<
" status() calls\n"
703 <<
T->NumOpenFileForReadCalls <<
" openFileForRead() calls\n"
704 <<
T->NumDirBeginCalls <<
" dir_begin() calls\n"
705 <<
T->NumGetRealPathCalls <<
" getRealPath() calls\n"
706 <<
T->NumExistsCalls <<
" exists() calls\n"
707 <<
T->NumIsLocalCalls <<
" isLocal() calls\n";
static llvm::Expected< DirectoryEntryRef > getDirectoryFromFile(FileManager &FileMgr, StringRef Filename, bool CacheFailure)
Retrieve the directory that the given file name resides in.
Defines the clang::FileManager interface and associated types.
Defines the FileSystemStatCache interface.
A reference to a DirectoryEntry that includes the name of the directory as it was accessed by the Fil...
StringRef getName() const
const DirectoryEntry & getDirEntry() const
Cached information about one directory (either on disk or in the virtual file system).
A reference to a FileEntry that includes the name of the file as it was accessed by the FileManager's...
const FileEntry & getFileEntry() const
StringRef getName() const
The name of this FileEntry.
DirectoryEntryRef getDir() const
Cached information about one file (either on disk or in the virtual file system).
bool isNamedPipe() const
Check whether the file is a named pipe (and thus can't be opened by the native FileManager methods).
Implements support for file system lookup, file system caching, and directory search management.
void AddStats(const FileManager &Other)
Import statistics from a child FileManager and add them to this current FileManager.
void trackVFSUsage(bool Active)
Enable or disable tracking of VFS usage.
void clearStatCache()
Removes the FileSystemStatCache object from the manager.
off_t time_t ModificationTime
llvm::vfs::FileSystem & getVirtualFileSystem() const
llvm::ErrorOr< std::unique_ptr< llvm::MemoryBuffer > > getBufferForFile(FileEntryRef Entry, bool isVolatile=false, bool RequiresNullTerminator=true, std::optional< int64_t > MaybeLimit=std::nullopt, bool IsText=true)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful,...
std::error_code getNoncachedStatValue(StringRef Path, llvm::vfs::Status &Result)
Get the 'stat' information for the given Path.
FileManager(const FileSystemOptions &FileSystemOpts, IntrusiveRefCntPtr< llvm::vfs::FileSystem > FS=nullptr)
Construct a file manager, optionally with a custom VFS.
llvm::Expected< FileEntryRef > getSTDIN()
Get the FileEntryRef for stdin, returning an error if stdin cannot be read.
StringRef getCanonicalName(DirectoryEntryRef Dir)
Retrieve the canonical name for a given directory.
void GetUniqueIDMapping(SmallVectorImpl< OptionalFileEntryRef > &UIDToFiles) const
Produce an array mapping from the unique IDs assigned to each file to the corresponding FileEntryRef.
bool makeAbsolutePath(SmallVectorImpl< char > &Path) const
Makes Path absolute taking into account FileSystemOptions and the working directory option.
llvm::Expected< DirectoryEntryRef > getDirectoryRef(StringRef DirName, bool CacheFailure=true)
Lookup, cache, and verify the specified directory (real or virtual).
void setStatCache(std::unique_ptr< FileSystemStatCache > statCache)
Installs the provided FileSystemStatCache object within the FileManager.
FileEntryRef getVirtualFileRef(StringRef Filename, off_t Size, time_t ModificationTime)
Retrieve a file entry for a "virtual" file that acts as if there were a file with the given name on d...
bool FixupRelativePath(SmallVectorImpl< char > &path) const
If path is not absolute and FileSystemOptions set the working directory, the path is modified to be r...
OptionalFileEntryRef getBypassFile(FileEntryRef VFE)
Retrieve a FileEntry that bypasses VFE, which is expected to be a virtual file entry,...
LLVM_DEPRECATED("Functions returning DirectoryEntry are deprecated.", "getOptionalDirectoryRef()") llvm LLVM_DEPRECATED("Functions returning FileEntry are deprecated.", "getOptionalFileRef()") llvm llvm::Expected< FileEntryRef > getFileRef(StringRef Filename, bool OpenFile=false, bool CacheFailure=true, bool IsText=true)
Lookup, cache, and verify the specified directory (real or virtual).
Keeps track of options that affect how file operations are performed.
std::string WorkingDir
If set, paths are resolved as if the working directory was set to the value of WorkingDir.
static std::error_code get(StringRef Path, llvm::vfs::Status &Status, bool isFile, std::unique_ptr< llvm::vfs::File > *F, FileSystemStatCache *Cache, llvm::vfs::FileSystem &FS, bool IsText=true)
Get the 'stat' information for the specified path, using the cache to accelerate it if possible.
The JSON file list parser is used to communicate input to InstallAPI.
std::error_code make_error_code(BuildPreambleError Error)
@ Result
The result type of a method or function.
const FunctionProtoType * T
@ Other
Other implicit parameter.
Type stored in the StringMap.