23 #include "llvm/ADT/SmallString.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"
32 #include <system_error>
34 using namespace clang;
38 #define NON_EXISTENT_DIR reinterpret_cast<DirectoryEntry*>((intptr_t)-1)
42 #define NON_EXISTENT_FILE reinterpret_cast<FileEntry*>((intptr_t)-1)
50 : FS(FS), FileSystemOpts(FSO),
51 SeenDirEntries(64), SeenFileEntries(64), NextFileUID(0) {
52 NumDirLookups = NumFileLookups = 0;
53 NumDirCacheMisses = NumFileCacheMisses = 0;
62 for (
unsigned i = 0, e = VirtualFileEntries.size(); i != e; ++i)
63 delete VirtualFileEntries[i];
64 for (
unsigned i = 0, e = VirtualDirectoryEntries.size(); i != e; ++i)
65 delete VirtualDirectoryEntries[i];
70 assert(statCache &&
"No stat cache provided?");
71 if (AtBeginning || !StatCache.get()) {
72 statCache->setNextStatCache(std::move(StatCache));
73 StatCache = std::move(statCache);
88 if (StatCache.get() == statCache) {
90 StatCache = StatCache->takeNextStatCache();
99 assert(PrevCache &&
"Stat cache not found for removal");
112 if (Filename.empty())
115 if (llvm::sys::path::is_separator(Filename[Filename.size() - 1]))
118 StringRef DirName = llvm::sys::path::parent_path(Filename);
128 void FileManager::addAncestorsAsVirtualDirs(StringRef Path) {
129 StringRef DirName = llvm::sys::path::parent_path(Path);
134 *SeenDirEntries.insert(std::make_pair(DirName,
nullptr)).first;
140 if (NamedDirEnt.second)
145 UDE->Name = NamedDirEnt.first().data();
146 NamedDirEnt.second = UDE;
147 VirtualDirectoryEntries.push_back(UDE);
150 addAncestorsAsVirtualDirs(DirName);
158 if (DirName.size() > 1 &&
159 DirName != llvm::sys::path::root_path(DirName) &&
160 llvm::sys::path::is_separator(DirName.back()))
161 DirName = DirName.substr(0, DirName.size()-1);
165 std::string DirNameStr;
166 if (DirName.size() > 1 && DirName.back() ==
':' &&
167 DirName.equals_lower(llvm::sys::path::root_name(DirName))) {
168 DirNameStr = DirName.str() +
'.';
169 DirName = DirNameStr;
175 *SeenDirEntries.insert(std::make_pair(DirName,
nullptr)).first;
179 if (NamedDirEnt.second)
181 : NamedDirEnt.second;
190 const char *InterndDirName = NamedDirEnt.first().data();
194 if (getStatValue(InterndDirName, Data,
false,
nullptr )) {
197 SeenDirEntries.erase(DirName);
207 NamedDirEnt.second = &UDE;
211 UDE.Name = InterndDirName;
223 *SeenFileEntries.insert(std::make_pair(Filename,
nullptr)).first;
226 if (NamedFileEnt.second)
228 : NamedFileEnt.second;
230 ++NumFileCacheMisses;
237 const char *InterndFileName = NamedFileEnt.first().data();
246 if (DirInfo ==
nullptr) {
248 SeenFileEntries.erase(Filename);
257 std::unique_ptr<vfs::File> F;
259 if (getStatValue(InterndFileName, Data,
true, openFile ? &F :
nullptr)) {
262 SeenFileEntries.erase(Filename);
267 assert((openFile || !F) &&
"undesired open file");
273 NamedFileEnt.second = &UFE;
277 if (Data.
Name != Filename) {
279 *SeenFileEntries.insert(std::make_pair(Data.
Name,
nullptr)).first;
280 if (!NamedFileEnt.second)
281 NamedFileEnt.second = &UFE;
283 assert(NamedFileEnt.second == &UFE &&
284 "filename from getStatValue() refers to wrong file");
285 InterndFileName = NamedFileEnt.first().data();
304 UFE.Name = InterndFileName;
310 UFE.Name = InterndFileName;
311 UFE.Size = Data.
Size;
314 UFE.UID = NextFileUID++;
317 UFE.InPCH = Data.
InPCH;
318 UFE.File = std::move(F);
325 time_t ModificationTime) {
330 *SeenFileEntries.insert(std::make_pair(Filename,
nullptr)).first;
334 return NamedFileEnt.second;
336 ++NumFileCacheMisses;
341 addAncestorsAsVirtualDirs(Filename);
350 "The directory of a virtual file should already be in the cache.");
354 const char *InterndFileName = NamedFileEnt.first().data();
355 if (getStatValue(InterndFileName, Data,
true,
nullptr) == 0) {
357 Data.
ModTime = ModificationTime;
358 UFE = &UniqueRealFiles[Data.
UniqueID];
360 NamedFileEnt.second = UFE;
374 UFE->InPCH = Data.
InPCH;
379 VirtualFileEntries.push_back(UFE);
380 NamedFileEnt.second = UFE;
383 UFE->Name = InterndFileName;
385 UFE->ModTime = ModificationTime;
387 UFE->UID = NextFileUID++;
393 StringRef pathRef(path.data(), path.size());
396 || llvm::sys::path::is_absolute(pathRef))
400 llvm::sys::path::append(NewPath, pathRef);
404 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
406 bool ShouldCloseOpenFile) {
407 uint64_t FileSize = Entry->
getSize();
413 const char *Filename = Entry->
getName();
417 Entry->File->getBuffer(Filename, FileSize,
421 if (ShouldCloseOpenFile)
429 return FS->getBufferForFile(Filename, FileSize,
434 return FS->getBufferForFile(FilePath, FileSize,
438 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
441 return FS->getBufferForFile(Filename);
445 return FS->getBufferForFile(FilePath.c_str());
453 bool FileManager::getStatValue(
const char *Path,
FileData &Data,
bool isFile,
454 std::unique_ptr<vfs::File> *F) {
464 StatCache.get(), *FS);
472 llvm::ErrorOr<vfs::Status>
S = FS->status(FilePath.c_str());
480 assert(Entry &&
"Cannot invalidate a NULL FileEntry");
482 SeenFileEntries.erase(Entry->
getName());
494 UIDToFiles.resize(NextFileUID);
497 for (llvm::StringMap<FileEntry*, llvm::BumpPtrAllocator>::const_iterator
498 FE = SeenFileEntries.begin(), FEEnd = SeenFileEntries.end();
501 UIDToFiles[FE->getValue()->getUID()] = FE->getValue();
505 VFE = VirtualFileEntries.begin(), VFEEnd = VirtualFileEntries.end();
506 VFE != VFEEnd; ++VFE)
508 UIDToFiles[(*VFE)->getUID()] = *VFE;
512 off_t Size, time_t ModificationTime) {
514 File->ModTime = ModificationTime;
521 using namespace llvm::sys;
524 StringRef
P(Path.data(), Path.size());
527 StringRef Rel = path::relative_path(
P);
528 bool AnyDots =
false;
529 for (StringRef
C : llvm::make_range(path::begin(Rel), path::end(Rel))) {
534 ComponentStack.push_back(
C);
541 for (StringRef
C : ComponentStack)
542 path::append(Buffer,
C);
550 llvm::DenseMap<const DirectoryEntry *, llvm::StringRef>::iterator Known
551 = CanonicalDirNames.find(Dir);
552 if (Known != CanonicalDirNames.end())
553 return Known->second;
555 StringRef CanonicalName(Dir->
getName());
558 char CanonicalNameBuf[PATH_MAX];
559 if (realpath(Dir->
getName(), CanonicalNameBuf)) {
560 unsigned Len = strlen(CanonicalNameBuf);
561 char *Mem =
static_cast<char *
>(CanonicalNameStorage.Allocate(Len, 1));
562 memcpy(Mem, CanonicalNameBuf, Len);
563 CanonicalName = StringRef(Mem, Len);
567 llvm::sys::fs::make_absolute(CanonicalNameBuf);
568 llvm::sys::path::native(CanonicalNameBuf);
572 CanonicalDirNames.insert(std::make_pair(Dir, CanonicalName));
573 return CanonicalName;
577 llvm::errs() <<
"\n*** File Manager Stats:\n";
578 llvm::errs() << UniqueRealFiles.size() <<
" real files found, "
579 << UniqueRealDirs.size() <<
" real dirs found.\n";
580 llvm::errs() << VirtualFileEntries.size() <<
" virtual files found, "
581 << VirtualDirectoryEntries.size() <<
" virtual dirs found.\n";
582 llvm::errs() << NumDirLookups <<
" dir lookups, "
583 << NumDirCacheMisses <<
" dir cache misses.\n";
584 llvm::errs() << NumFileLookups <<
" file lookups, "
585 << NumFileCacheMisses <<
" file cache misses.\n";
static bool removeDotPaths(SmallVectorImpl< char > &Path)
Remove any './' components from a path.
Implements support for file system lookup, file system caching, and directory search management...
Defines the clang::FileManager interface and associated types.
IntrusiveRefCntPtr< FileSystem > getRealFileSystem()
Gets an vfs::FileSystem for the 'real' file system, as seen by the operating system.
Defines the FileSystemStatCache interface.
FileManager(const FileSystemOptions &FileSystemOpts, IntrusiveRefCntPtr< vfs::FileSystem > FS=nullptr)
static bool get(const char *Path, FileData &Data, bool isFile, std::unique_ptr< vfs::File > *F, FileSystemStatCache *Cache, vfs::FileSystem &FS)
Get the 'stat' information for the specified path, using the cache to accelerate it if possible...
void FixupRelativePath(SmallVectorImpl< char > &path) const
If path is not absolute and FileSystemOptions set the working directory, the path is modified to be r...
#define NON_EXISTENT_FILE
Abstract interface for introducing a FileManager cache for 'stat' system calls, which is used by prec...
std::unique_ptr< FileSystemStatCache > takeNextStatCache()
Retrieve the next stat call cache in the chain, transferring ownership of this cache (and...
The result of a status operation.
const FileEntry * getFile(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Lookup, cache, and verify the specified file (real or virtual).
const DirectoryEntry * getDirectory(StringRef DirName, bool CacheFailure=true)
Lookup, cache, and verify the specified directory (real or virtual).
static const DirectoryEntry * getDirectoryFromFile(FileManager &FileMgr, StringRef Filename, bool CacheFailure)
Retrieve the directory that the given file name resides in. Filename can point to either a real file ...
const llvm::sys::fs::UniqueID & getUniqueID() const
void setNextStatCache(std::unique_ptr< FileSystemStatCache > Cache)
Sets the next stat call cache in the chain of stat caches. Takes ownership of the given stat cache...
std::string WorkingDir
If set, paths are resolved as if the working directory was set to the value of WorkingDir.
The result type of a method or function.
void addStatCache(std::unique_ptr< FileSystemStatCache > statCache, bool AtBeginning=false)
Installs the provided FileSystemStatCache object within the FileManager.
const char * getName() const
llvm::sys::fs::UniqueID UniqueID
Cached information about one file (either on disk or in the virtual file system). ...
void clearStatCaches()
Removes all FileSystemStatCache objects from the manager.
virtual ~PCHContainerReader()=0
const FileEntry * getVirtualFile(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...
const char * getName() const
StringRef getCanonicalName(const DirectoryEntry *Dir)
Retrieve the canonical name for a given directory.
void removeStatCache(FileSystemStatCache *statCache)
Removes the specified FileSystemStatCache object from the manager.
llvm::ErrorOr< std::unique_ptr< llvm::MemoryBuffer > > getBufferForFile(const FileEntry *Entry, bool isVolatile=false, bool ShouldCloseOpenFile=true)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful, otherwise returning null.
Cached information about one directory (either on disk or in the virtual file system).
Keeps track of options that affect how file operations are performed.
bool getNoncachedStatValue(StringRef Path, vfs::Status &Result)
Get the 'stat' information for the given Path.
static void modifyFileEntry(FileEntry *File, off_t Size, time_t ModificationTime)
Modifies the size and modification time of a previously created FileEntry. Use with caution...
void invalidateCache(const FileEntry *Entry)
Remove the real file Entry from the cache.
virtual ~PCHContainerWriter()=0
FileSystemStatCache * getNextStatCache()
Retrieve the next stat call cache in the chain.
void GetUniqueIDMapping(SmallVectorImpl< const FileEntry * > &UIDToFiles) const
Produce an array mapping from the unique IDs assigned to each file to the corresponding FileEntry poi...