17330f729Sjoerg //===--- FileManager.cpp - File System Probing and Caching ----------------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This file implements the FileManager interface.
107330f729Sjoerg //
117330f729Sjoerg //===----------------------------------------------------------------------===//
127330f729Sjoerg //
137330f729Sjoerg // TODO: This should index all interesting directories with dirent calls.
147330f729Sjoerg // getdirentries ?
157330f729Sjoerg // opendir/readdir_r/closedir ?
167330f729Sjoerg //
177330f729Sjoerg //===----------------------------------------------------------------------===//
187330f729Sjoerg
197330f729Sjoerg #include "clang/Basic/FileManager.h"
207330f729Sjoerg #include "clang/Basic/FileSystemStatCache.h"
217330f729Sjoerg #include "llvm/ADT/STLExtras.h"
227330f729Sjoerg #include "llvm/ADT/SmallString.h"
237330f729Sjoerg #include "llvm/ADT/Statistic.h"
247330f729Sjoerg #include "llvm/Config/llvm-config.h"
257330f729Sjoerg #include "llvm/Support/FileSystem.h"
267330f729Sjoerg #include "llvm/Support/MemoryBuffer.h"
277330f729Sjoerg #include "llvm/Support/Path.h"
287330f729Sjoerg #include "llvm/Support/raw_ostream.h"
297330f729Sjoerg #include <algorithm>
307330f729Sjoerg #include <cassert>
317330f729Sjoerg #include <climits>
327330f729Sjoerg #include <cstdint>
337330f729Sjoerg #include <cstdlib>
347330f729Sjoerg #include <string>
357330f729Sjoerg #include <utility>
367330f729Sjoerg
377330f729Sjoerg using namespace clang;
387330f729Sjoerg
397330f729Sjoerg #define DEBUG_TYPE "file-search"
407330f729Sjoerg
417330f729Sjoerg ALWAYS_ENABLED_STATISTIC(NumDirLookups, "Number of directory lookups.");
427330f729Sjoerg ALWAYS_ENABLED_STATISTIC(NumFileLookups, "Number of file lookups.");
437330f729Sjoerg ALWAYS_ENABLED_STATISTIC(NumDirCacheMisses,
447330f729Sjoerg "Number of directory cache misses.");
457330f729Sjoerg ALWAYS_ENABLED_STATISTIC(NumFileCacheMisses, "Number of file cache misses.");
467330f729Sjoerg
477330f729Sjoerg //===----------------------------------------------------------------------===//
487330f729Sjoerg // Common logic.
497330f729Sjoerg //===----------------------------------------------------------------------===//
507330f729Sjoerg
FileManager(const FileSystemOptions & FSO,IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)517330f729Sjoerg FileManager::FileManager(const FileSystemOptions &FSO,
527330f729Sjoerg IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)
537330f729Sjoerg : FS(std::move(FS)), FileSystemOpts(FSO), SeenDirEntries(64),
547330f729Sjoerg SeenFileEntries(64), NextFileUID(0) {
557330f729Sjoerg // If the caller doesn't provide a virtual file system, just grab the real
567330f729Sjoerg // file system.
577330f729Sjoerg if (!this->FS)
587330f729Sjoerg this->FS = llvm::vfs::getRealFileSystem();
597330f729Sjoerg }
607330f729Sjoerg
617330f729Sjoerg FileManager::~FileManager() = default;
627330f729Sjoerg
setStatCache(std::unique_ptr<FileSystemStatCache> statCache)637330f729Sjoerg void FileManager::setStatCache(std::unique_ptr<FileSystemStatCache> statCache) {
647330f729Sjoerg assert(statCache && "No stat cache provided?");
657330f729Sjoerg StatCache = std::move(statCache);
667330f729Sjoerg }
677330f729Sjoerg
clearStatCache()687330f729Sjoerg void FileManager::clearStatCache() { StatCache.reset(); }
697330f729Sjoerg
707330f729Sjoerg /// Retrieve the directory that the given file name resides in.
717330f729Sjoerg /// Filename can point to either a real file or a virtual file.
72*e038c9c4Sjoerg static llvm::Expected<DirectoryEntryRef>
getDirectoryFromFile(FileManager & FileMgr,StringRef Filename,bool CacheFailure)737330f729Sjoerg getDirectoryFromFile(FileManager &FileMgr, StringRef Filename,
747330f729Sjoerg bool CacheFailure) {
757330f729Sjoerg if (Filename.empty())
76*e038c9c4Sjoerg return llvm::errorCodeToError(
77*e038c9c4Sjoerg make_error_code(std::errc::no_such_file_or_directory));
787330f729Sjoerg
797330f729Sjoerg if (llvm::sys::path::is_separator(Filename[Filename.size() - 1]))
80*e038c9c4Sjoerg return llvm::errorCodeToError(make_error_code(std::errc::is_a_directory));
817330f729Sjoerg
827330f729Sjoerg StringRef DirName = llvm::sys::path::parent_path(Filename);
837330f729Sjoerg // Use the current directory if file has no path component.
847330f729Sjoerg if (DirName.empty())
857330f729Sjoerg DirName = ".";
867330f729Sjoerg
87*e038c9c4Sjoerg return FileMgr.getDirectoryRef(DirName, CacheFailure);
887330f729Sjoerg }
897330f729Sjoerg
907330f729Sjoerg /// Add all ancestors of the given path (pointing to either a file or
917330f729Sjoerg /// a directory) as virtual directories.
addAncestorsAsVirtualDirs(StringRef Path)927330f729Sjoerg void FileManager::addAncestorsAsVirtualDirs(StringRef Path) {
937330f729Sjoerg StringRef DirName = llvm::sys::path::parent_path(Path);
947330f729Sjoerg if (DirName.empty())
957330f729Sjoerg DirName = ".";
967330f729Sjoerg
977330f729Sjoerg auto &NamedDirEnt = *SeenDirEntries.insert(
987330f729Sjoerg {DirName, std::errc::no_such_file_or_directory}).first;
997330f729Sjoerg
1007330f729Sjoerg // When caching a virtual directory, we always cache its ancestors
1017330f729Sjoerg // at the same time. Therefore, if DirName is already in the cache,
1027330f729Sjoerg // we don't need to recurse as its ancestors must also already be in
1037330f729Sjoerg // the cache (or it's a known non-virtual directory).
1047330f729Sjoerg if (NamedDirEnt.second)
1057330f729Sjoerg return;
1067330f729Sjoerg
1077330f729Sjoerg // Add the virtual directory to the cache.
1087330f729Sjoerg auto UDE = std::make_unique<DirectoryEntry>();
1097330f729Sjoerg UDE->Name = NamedDirEnt.first();
1107330f729Sjoerg NamedDirEnt.second = *UDE.get();
1117330f729Sjoerg VirtualDirectoryEntries.push_back(std::move(UDE));
1127330f729Sjoerg
1137330f729Sjoerg // Recursively add the other ancestors.
1147330f729Sjoerg addAncestorsAsVirtualDirs(DirName);
1157330f729Sjoerg }
1167330f729Sjoerg
1177330f729Sjoerg llvm::Expected<DirectoryEntryRef>
getDirectoryRef(StringRef DirName,bool CacheFailure)1187330f729Sjoerg FileManager::getDirectoryRef(StringRef DirName, bool CacheFailure) {
1197330f729Sjoerg // stat doesn't like trailing separators except for root directory.
1207330f729Sjoerg // At least, on Win32 MSVCRT, stat() cannot strip trailing '/'.
1217330f729Sjoerg // (though it can strip '\\')
1227330f729Sjoerg if (DirName.size() > 1 &&
1237330f729Sjoerg DirName != llvm::sys::path::root_path(DirName) &&
1247330f729Sjoerg llvm::sys::path::is_separator(DirName.back()))
1257330f729Sjoerg DirName = DirName.substr(0, DirName.size()-1);
1267330f729Sjoerg #ifdef _WIN32
1277330f729Sjoerg // Fixing a problem with "clang C:test.c" on Windows.
1287330f729Sjoerg // Stat("C:") does not recognize "C:" as a valid directory
1297330f729Sjoerg std::string DirNameStr;
1307330f729Sjoerg if (DirName.size() > 1 && DirName.back() == ':' &&
1317330f729Sjoerg DirName.equals_lower(llvm::sys::path::root_name(DirName))) {
1327330f729Sjoerg DirNameStr = DirName.str() + '.';
1337330f729Sjoerg DirName = DirNameStr;
1347330f729Sjoerg }
1357330f729Sjoerg #endif
1367330f729Sjoerg
1377330f729Sjoerg ++NumDirLookups;
1387330f729Sjoerg
1397330f729Sjoerg // See if there was already an entry in the map. Note that the map
1407330f729Sjoerg // contains both virtual and real directories.
1417330f729Sjoerg auto SeenDirInsertResult =
1427330f729Sjoerg SeenDirEntries.insert({DirName, std::errc::no_such_file_or_directory});
1437330f729Sjoerg if (!SeenDirInsertResult.second) {
1447330f729Sjoerg if (SeenDirInsertResult.first->second)
145*e038c9c4Sjoerg return DirectoryEntryRef(*SeenDirInsertResult.first);
1467330f729Sjoerg return llvm::errorCodeToError(SeenDirInsertResult.first->second.getError());
1477330f729Sjoerg }
1487330f729Sjoerg
1497330f729Sjoerg // We've not seen this before. Fill it in.
1507330f729Sjoerg ++NumDirCacheMisses;
1517330f729Sjoerg auto &NamedDirEnt = *SeenDirInsertResult.first;
1527330f729Sjoerg assert(!NamedDirEnt.second && "should be newly-created");
1537330f729Sjoerg
1547330f729Sjoerg // Get the null-terminated directory name as stored as the key of the
1557330f729Sjoerg // SeenDirEntries map.
1567330f729Sjoerg StringRef InterndDirName = NamedDirEnt.first();
1577330f729Sjoerg
1587330f729Sjoerg // Check to see if the directory exists.
1597330f729Sjoerg llvm::vfs::Status Status;
1607330f729Sjoerg auto statError = getStatValue(InterndDirName, Status, false,
1617330f729Sjoerg nullptr /*directory lookup*/);
1627330f729Sjoerg if (statError) {
1637330f729Sjoerg // There's no real directory at the given path.
1647330f729Sjoerg if (CacheFailure)
1657330f729Sjoerg NamedDirEnt.second = statError;
1667330f729Sjoerg else
1677330f729Sjoerg SeenDirEntries.erase(DirName);
1687330f729Sjoerg return llvm::errorCodeToError(statError);
1697330f729Sjoerg }
1707330f729Sjoerg
1717330f729Sjoerg // It exists. See if we have already opened a directory with the
1727330f729Sjoerg // same inode (this occurs on Unix-like systems when one dir is
1737330f729Sjoerg // symlinked to another, for example) or the same path (on
1747330f729Sjoerg // Windows).
1757330f729Sjoerg DirectoryEntry &UDE = UniqueRealDirs[Status.getUniqueID()];
1767330f729Sjoerg
1777330f729Sjoerg NamedDirEnt.second = UDE;
1787330f729Sjoerg if (UDE.getName().empty()) {
1797330f729Sjoerg // We don't have this directory yet, add it. We use the string
1807330f729Sjoerg // key from the SeenDirEntries map as the string.
1817330f729Sjoerg UDE.Name = InterndDirName;
1827330f729Sjoerg }
1837330f729Sjoerg
184*e038c9c4Sjoerg return DirectoryEntryRef(NamedDirEnt);
1857330f729Sjoerg }
1867330f729Sjoerg
1877330f729Sjoerg llvm::ErrorOr<const DirectoryEntry *>
getDirectory(StringRef DirName,bool CacheFailure)1887330f729Sjoerg FileManager::getDirectory(StringRef DirName, bool CacheFailure) {
1897330f729Sjoerg auto Result = getDirectoryRef(DirName, CacheFailure);
1907330f729Sjoerg if (Result)
1917330f729Sjoerg return &Result->getDirEntry();
1927330f729Sjoerg return llvm::errorToErrorCode(Result.takeError());
1937330f729Sjoerg }
1947330f729Sjoerg
1957330f729Sjoerg llvm::ErrorOr<const FileEntry *>
getFile(StringRef Filename,bool openFile,bool CacheFailure)1967330f729Sjoerg FileManager::getFile(StringRef Filename, bool openFile, bool CacheFailure) {
1977330f729Sjoerg auto Result = getFileRef(Filename, openFile, CacheFailure);
1987330f729Sjoerg if (Result)
1997330f729Sjoerg return &Result->getFileEntry();
2007330f729Sjoerg return llvm::errorToErrorCode(Result.takeError());
2017330f729Sjoerg }
2027330f729Sjoerg
2037330f729Sjoerg llvm::Expected<FileEntryRef>
getFileRef(StringRef Filename,bool openFile,bool CacheFailure)2047330f729Sjoerg FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) {
2057330f729Sjoerg ++NumFileLookups;
2067330f729Sjoerg
2077330f729Sjoerg // See if there is already an entry in the map.
2087330f729Sjoerg auto SeenFileInsertResult =
2097330f729Sjoerg SeenFileEntries.insert({Filename, std::errc::no_such_file_or_directory});
2107330f729Sjoerg if (!SeenFileInsertResult.second) {
2117330f729Sjoerg if (!SeenFileInsertResult.first->second)
2127330f729Sjoerg return llvm::errorCodeToError(
2137330f729Sjoerg SeenFileInsertResult.first->second.getError());
2147330f729Sjoerg // Construct and return and FileEntryRef, unless it's a redirect to another
2157330f729Sjoerg // filename.
216*e038c9c4Sjoerg FileEntryRef::MapValue Value = *SeenFileInsertResult.first->second;
217*e038c9c4Sjoerg if (LLVM_LIKELY(Value.V.is<FileEntry *>()))
218*e038c9c4Sjoerg return FileEntryRef(*SeenFileInsertResult.first);
219*e038c9c4Sjoerg return FileEntryRef(*reinterpret_cast<const FileEntryRef::MapEntry *>(
220*e038c9c4Sjoerg Value.V.get<const void *>()));
2217330f729Sjoerg }
2227330f729Sjoerg
2237330f729Sjoerg // We've not seen this before. Fill it in.
2247330f729Sjoerg ++NumFileCacheMisses;
225*e038c9c4Sjoerg auto *NamedFileEnt = &*SeenFileInsertResult.first;
226*e038c9c4Sjoerg assert(!NamedFileEnt->second && "should be newly-created");
2277330f729Sjoerg
2287330f729Sjoerg // Get the null-terminated file name as stored as the key of the
2297330f729Sjoerg // SeenFileEntries map.
230*e038c9c4Sjoerg StringRef InterndFileName = NamedFileEnt->first();
2317330f729Sjoerg
2327330f729Sjoerg // Look up the directory for the file. When looking up something like
2337330f729Sjoerg // sys/foo.h we'll discover all of the search directories that have a 'sys'
2347330f729Sjoerg // subdirectory. This will let us avoid having to waste time on known-to-fail
2357330f729Sjoerg // searches when we go to find sys/bar.h, because all the search directories
2367330f729Sjoerg // without a 'sys' subdir will get a cached failure result.
2377330f729Sjoerg auto DirInfoOrErr = getDirectoryFromFile(*this, Filename, CacheFailure);
2387330f729Sjoerg if (!DirInfoOrErr) { // Directory doesn't exist, file can't exist.
239*e038c9c4Sjoerg std::error_code Err = errorToErrorCode(DirInfoOrErr.takeError());
2407330f729Sjoerg if (CacheFailure)
241*e038c9c4Sjoerg NamedFileEnt->second = Err;
2427330f729Sjoerg else
2437330f729Sjoerg SeenFileEntries.erase(Filename);
2447330f729Sjoerg
245*e038c9c4Sjoerg return llvm::errorCodeToError(Err);
2467330f729Sjoerg }
247*e038c9c4Sjoerg DirectoryEntryRef DirInfo = *DirInfoOrErr;
2487330f729Sjoerg
2497330f729Sjoerg // FIXME: Use the directory info to prune this, before doing the stat syscall.
2507330f729Sjoerg // FIXME: This will reduce the # syscalls.
2517330f729Sjoerg
2527330f729Sjoerg // Check to see if the file exists.
2537330f729Sjoerg std::unique_ptr<llvm::vfs::File> F;
2547330f729Sjoerg llvm::vfs::Status Status;
2557330f729Sjoerg auto statError = getStatValue(InterndFileName, Status, true,
2567330f729Sjoerg openFile ? &F : nullptr);
2577330f729Sjoerg if (statError) {
2587330f729Sjoerg // There's no real file at the given path.
2597330f729Sjoerg if (CacheFailure)
260*e038c9c4Sjoerg NamedFileEnt->second = statError;
2617330f729Sjoerg else
2627330f729Sjoerg SeenFileEntries.erase(Filename);
2637330f729Sjoerg
2647330f729Sjoerg return llvm::errorCodeToError(statError);
2657330f729Sjoerg }
2667330f729Sjoerg
2677330f729Sjoerg assert((openFile || !F) && "undesired open file");
2687330f729Sjoerg
2697330f729Sjoerg // It exists. See if we have already opened a file with the same inode.
2707330f729Sjoerg // This occurs when one dir is symlinked to another, for example.
2717330f729Sjoerg FileEntry &UFE = UniqueRealFiles[Status.getUniqueID()];
2727330f729Sjoerg
273*e038c9c4Sjoerg if (Status.getName() == Filename) {
274*e038c9c4Sjoerg // The name matches. Set the FileEntry.
275*e038c9c4Sjoerg NamedFileEnt->second = FileEntryRef::MapValue(UFE, DirInfo);
276*e038c9c4Sjoerg } else {
277*e038c9c4Sjoerg // Name mismatch. We need a redirect. First grab the actual entry we want
278*e038c9c4Sjoerg // to return.
279*e038c9c4Sjoerg auto &Redirection =
280*e038c9c4Sjoerg *SeenFileEntries
281*e038c9c4Sjoerg .insert({Status.getName(), FileEntryRef::MapValue(UFE, DirInfo)})
282*e038c9c4Sjoerg .first;
283*e038c9c4Sjoerg assert(Redirection.second->V.is<FileEntry *>() &&
284*e038c9c4Sjoerg "filename redirected to a non-canonical filename?");
285*e038c9c4Sjoerg assert(Redirection.second->V.get<FileEntry *>() == &UFE &&
2867330f729Sjoerg "filename from getStatValue() refers to wrong file");
287*e038c9c4Sjoerg
288*e038c9c4Sjoerg // Cache the redirection in the previously-inserted entry, still available
289*e038c9c4Sjoerg // in the tentative return value.
290*e038c9c4Sjoerg NamedFileEnt->second = FileEntryRef::MapValue(Redirection);
291*e038c9c4Sjoerg
292*e038c9c4Sjoerg // Fix the tentative return value.
293*e038c9c4Sjoerg NamedFileEnt = &Redirection;
2947330f729Sjoerg }
2957330f729Sjoerg
296*e038c9c4Sjoerg FileEntryRef ReturnedRef(*NamedFileEnt);
2977330f729Sjoerg if (UFE.isValid()) { // Already have an entry with this inode, return it.
2987330f729Sjoerg
2997330f729Sjoerg // FIXME: this hack ensures that if we look up a file by a virtual path in
3007330f729Sjoerg // the VFS that the getDir() will have the virtual path, even if we found
3017330f729Sjoerg // the file by a 'real' path first. This is required in order to find a
3027330f729Sjoerg // module's structure when its headers/module map are mapped in the VFS.
3037330f729Sjoerg // We should remove this as soon as we can properly support a file having
3047330f729Sjoerg // multiple names.
305*e038c9c4Sjoerg if (&DirInfo.getDirEntry() != UFE.Dir && Status.IsVFSMapped)
306*e038c9c4Sjoerg UFE.Dir = &DirInfo.getDirEntry();
3077330f729Sjoerg
308*e038c9c4Sjoerg // Always update LastRef to the last name by which a file was accessed.
309*e038c9c4Sjoerg // FIXME: Neither this nor always using the first reference is correct; we
310*e038c9c4Sjoerg // want to switch towards a design where we return a FileName object that
3117330f729Sjoerg // encapsulates both the name by which the file was accessed and the
3127330f729Sjoerg // corresponding FileEntry.
313*e038c9c4Sjoerg // FIXME: LastRef should be removed from FileEntry once all clients adopt
314*e038c9c4Sjoerg // FileEntryRef.
315*e038c9c4Sjoerg UFE.LastRef = ReturnedRef;
3167330f729Sjoerg
317*e038c9c4Sjoerg return ReturnedRef;
3187330f729Sjoerg }
3197330f729Sjoerg
3207330f729Sjoerg // Otherwise, we don't have this file yet, add it.
321*e038c9c4Sjoerg UFE.LastRef = ReturnedRef;
3227330f729Sjoerg UFE.Size = Status.getSize();
3237330f729Sjoerg UFE.ModTime = llvm::sys::toTimeT(Status.getLastModificationTime());
324*e038c9c4Sjoerg UFE.Dir = &DirInfo.getDirEntry();
3257330f729Sjoerg UFE.UID = NextFileUID++;
3267330f729Sjoerg UFE.UniqueID = Status.getUniqueID();
3277330f729Sjoerg UFE.IsNamedPipe = Status.getType() == llvm::sys::fs::file_type::fifo_file;
3287330f729Sjoerg UFE.File = std::move(F);
3297330f729Sjoerg UFE.IsValid = true;
3307330f729Sjoerg
3317330f729Sjoerg if (UFE.File) {
3327330f729Sjoerg if (auto PathName = UFE.File->getName())
3337330f729Sjoerg fillRealPathName(&UFE, *PathName);
3347330f729Sjoerg } else if (!openFile) {
3357330f729Sjoerg // We should still fill the path even if we aren't opening the file.
3367330f729Sjoerg fillRealPathName(&UFE, InterndFileName);
3377330f729Sjoerg }
338*e038c9c4Sjoerg return ReturnedRef;
3397330f729Sjoerg }
3407330f729Sjoerg
getSTDIN()341*e038c9c4Sjoerg llvm::Expected<FileEntryRef> FileManager::getSTDIN() {
342*e038c9c4Sjoerg // Only read stdin once.
343*e038c9c4Sjoerg if (STDIN)
344*e038c9c4Sjoerg return *STDIN;
345*e038c9c4Sjoerg
346*e038c9c4Sjoerg std::unique_ptr<llvm::MemoryBuffer> Content;
347*e038c9c4Sjoerg if (auto ContentOrError = llvm::MemoryBuffer::getSTDIN())
348*e038c9c4Sjoerg Content = std::move(*ContentOrError);
349*e038c9c4Sjoerg else
350*e038c9c4Sjoerg return llvm::errorCodeToError(ContentOrError.getError());
351*e038c9c4Sjoerg
352*e038c9c4Sjoerg STDIN = getVirtualFileRef(Content->getBufferIdentifier(),
353*e038c9c4Sjoerg Content->getBufferSize(), 0);
354*e038c9c4Sjoerg FileEntry &FE = const_cast<FileEntry &>(STDIN->getFileEntry());
355*e038c9c4Sjoerg FE.Content = std::move(Content);
356*e038c9c4Sjoerg FE.IsNamedPipe = true;
357*e038c9c4Sjoerg return *STDIN;
358*e038c9c4Sjoerg }
359*e038c9c4Sjoerg
getVirtualFile(StringRef Filename,off_t Size,time_t ModificationTime)360*e038c9c4Sjoerg const FileEntry *FileManager::getVirtualFile(StringRef Filename, off_t Size,
361*e038c9c4Sjoerg time_t ModificationTime) {
362*e038c9c4Sjoerg return &getVirtualFileRef(Filename, Size, ModificationTime).getFileEntry();
363*e038c9c4Sjoerg }
364*e038c9c4Sjoerg
getVirtualFileRef(StringRef Filename,off_t Size,time_t ModificationTime)365*e038c9c4Sjoerg FileEntryRef FileManager::getVirtualFileRef(StringRef Filename, off_t Size,
3667330f729Sjoerg time_t ModificationTime) {
3677330f729Sjoerg ++NumFileLookups;
3687330f729Sjoerg
3697330f729Sjoerg // See if there is already an entry in the map for an existing file.
3707330f729Sjoerg auto &NamedFileEnt = *SeenFileEntries.insert(
3717330f729Sjoerg {Filename, std::errc::no_such_file_or_directory}).first;
3727330f729Sjoerg if (NamedFileEnt.second) {
373*e038c9c4Sjoerg FileEntryRef::MapValue Value = *NamedFileEnt.second;
374*e038c9c4Sjoerg if (LLVM_LIKELY(Value.V.is<FileEntry *>()))
375*e038c9c4Sjoerg return FileEntryRef(NamedFileEnt);
376*e038c9c4Sjoerg return FileEntryRef(*reinterpret_cast<const FileEntryRef::MapEntry *>(
377*e038c9c4Sjoerg Value.V.get<const void *>()));
3787330f729Sjoerg }
3797330f729Sjoerg
3807330f729Sjoerg // We've not seen this before, or the file is cached as non-existent.
3817330f729Sjoerg ++NumFileCacheMisses;
3827330f729Sjoerg addAncestorsAsVirtualDirs(Filename);
3837330f729Sjoerg FileEntry *UFE = nullptr;
3847330f729Sjoerg
3857330f729Sjoerg // Now that all ancestors of Filename are in the cache, the
3867330f729Sjoerg // following call is guaranteed to find the DirectoryEntry from the
387*e038c9c4Sjoerg // cache. A virtual file can also have an empty filename, that could come
388*e038c9c4Sjoerg // from a source location preprocessor directive with an empty filename as
389*e038c9c4Sjoerg // an example, so we need to pretend it has a name to ensure a valid directory
390*e038c9c4Sjoerg // entry can be returned.
391*e038c9c4Sjoerg auto DirInfo = expectedToOptional(getDirectoryFromFile(
392*e038c9c4Sjoerg *this, Filename.empty() ? "." : Filename, /*CacheFailure=*/true));
3937330f729Sjoerg assert(DirInfo &&
3947330f729Sjoerg "The directory of a virtual file should already be in the cache.");
3957330f729Sjoerg
3967330f729Sjoerg // Check to see if the file exists. If so, drop the virtual file
3977330f729Sjoerg llvm::vfs::Status Status;
3987330f729Sjoerg const char *InterndFileName = NamedFileEnt.first().data();
3997330f729Sjoerg if (!getStatValue(InterndFileName, Status, true, nullptr)) {
4007330f729Sjoerg UFE = &UniqueRealFiles[Status.getUniqueID()];
4017330f729Sjoerg Status = llvm::vfs::Status(
4027330f729Sjoerg Status.getName(), Status.getUniqueID(),
4037330f729Sjoerg llvm::sys::toTimePoint(ModificationTime),
4047330f729Sjoerg Status.getUser(), Status.getGroup(), Size,
4057330f729Sjoerg Status.getType(), Status.getPermissions());
4067330f729Sjoerg
407*e038c9c4Sjoerg NamedFileEnt.second = FileEntryRef::MapValue(*UFE, *DirInfo);
4087330f729Sjoerg
4097330f729Sjoerg // If we had already opened this file, close it now so we don't
4107330f729Sjoerg // leak the descriptor. We're not going to use the file
4117330f729Sjoerg // descriptor anyway, since this is a virtual file.
4127330f729Sjoerg if (UFE->File)
4137330f729Sjoerg UFE->closeFile();
4147330f729Sjoerg
4157330f729Sjoerg // If we already have an entry with this inode, return it.
416*e038c9c4Sjoerg //
417*e038c9c4Sjoerg // FIXME: Surely this should add a reference by the new name, and return
418*e038c9c4Sjoerg // it instead...
4197330f729Sjoerg if (UFE->isValid())
420*e038c9c4Sjoerg return FileEntryRef(NamedFileEnt);
4217330f729Sjoerg
4227330f729Sjoerg UFE->UniqueID = Status.getUniqueID();
4237330f729Sjoerg UFE->IsNamedPipe = Status.getType() == llvm::sys::fs::file_type::fifo_file;
4247330f729Sjoerg fillRealPathName(UFE, Status.getName());
4257330f729Sjoerg } else {
4267330f729Sjoerg VirtualFileEntries.push_back(std::make_unique<FileEntry>());
4277330f729Sjoerg UFE = VirtualFileEntries.back().get();
428*e038c9c4Sjoerg NamedFileEnt.second = FileEntryRef::MapValue(*UFE, *DirInfo);
4297330f729Sjoerg }
4307330f729Sjoerg
431*e038c9c4Sjoerg UFE->LastRef = FileEntryRef(NamedFileEnt);
4327330f729Sjoerg UFE->Size = Size;
4337330f729Sjoerg UFE->ModTime = ModificationTime;
434*e038c9c4Sjoerg UFE->Dir = &DirInfo->getDirEntry();
4357330f729Sjoerg UFE->UID = NextFileUID++;
4367330f729Sjoerg UFE->IsValid = true;
4377330f729Sjoerg UFE->File.reset();
438*e038c9c4Sjoerg return FileEntryRef(NamedFileEnt);
4397330f729Sjoerg }
4407330f729Sjoerg
getBypassFile(FileEntryRef VF)4417330f729Sjoerg llvm::Optional<FileEntryRef> FileManager::getBypassFile(FileEntryRef VF) {
4427330f729Sjoerg // Stat of the file and return nullptr if it doesn't exist.
4437330f729Sjoerg llvm::vfs::Status Status;
4447330f729Sjoerg if (getStatValue(VF.getName(), Status, /*isFile=*/true, /*F=*/nullptr))
4457330f729Sjoerg return None;
4467330f729Sjoerg
447*e038c9c4Sjoerg if (!SeenBypassFileEntries)
448*e038c9c4Sjoerg SeenBypassFileEntries = std::make_unique<
449*e038c9c4Sjoerg llvm::StringMap<llvm::ErrorOr<FileEntryRef::MapValue>>>();
450*e038c9c4Sjoerg
451*e038c9c4Sjoerg // If we've already bypassed just use the existing one.
452*e038c9c4Sjoerg auto Insertion = SeenBypassFileEntries->insert(
453*e038c9c4Sjoerg {VF.getName(), std::errc::no_such_file_or_directory});
454*e038c9c4Sjoerg if (!Insertion.second)
455*e038c9c4Sjoerg return FileEntryRef(*Insertion.first);
456*e038c9c4Sjoerg
457*e038c9c4Sjoerg // Fill in the new entry from the stat.
4587330f729Sjoerg BypassFileEntries.push_back(std::make_unique<FileEntry>());
4597330f729Sjoerg const FileEntry &VFE = VF.getFileEntry();
4607330f729Sjoerg FileEntry &BFE = *BypassFileEntries.back();
461*e038c9c4Sjoerg Insertion.first->second = FileEntryRef::MapValue(BFE, VF.getDir());
462*e038c9c4Sjoerg BFE.LastRef = FileEntryRef(*Insertion.first);
4637330f729Sjoerg BFE.Size = Status.getSize();
4647330f729Sjoerg BFE.Dir = VFE.Dir;
4657330f729Sjoerg BFE.ModTime = llvm::sys::toTimeT(Status.getLastModificationTime());
4667330f729Sjoerg BFE.UID = NextFileUID++;
4677330f729Sjoerg BFE.IsValid = true;
468*e038c9c4Sjoerg
469*e038c9c4Sjoerg // Save the entry in the bypass table and return.
470*e038c9c4Sjoerg return FileEntryRef(*Insertion.first);
4717330f729Sjoerg }
4727330f729Sjoerg
FixupRelativePath(SmallVectorImpl<char> & path) const4737330f729Sjoerg bool FileManager::FixupRelativePath(SmallVectorImpl<char> &path) const {
4747330f729Sjoerg StringRef pathRef(path.data(), path.size());
4757330f729Sjoerg
4767330f729Sjoerg if (FileSystemOpts.WorkingDir.empty()
4777330f729Sjoerg || llvm::sys::path::is_absolute(pathRef))
4787330f729Sjoerg return false;
4797330f729Sjoerg
4807330f729Sjoerg SmallString<128> NewPath(FileSystemOpts.WorkingDir);
4817330f729Sjoerg llvm::sys::path::append(NewPath, pathRef);
4827330f729Sjoerg path = NewPath;
4837330f729Sjoerg return true;
4847330f729Sjoerg }
4857330f729Sjoerg
makeAbsolutePath(SmallVectorImpl<char> & Path) const4867330f729Sjoerg bool FileManager::makeAbsolutePath(SmallVectorImpl<char> &Path) const {
4877330f729Sjoerg bool Changed = FixupRelativePath(Path);
4887330f729Sjoerg
4897330f729Sjoerg if (!llvm::sys::path::is_absolute(StringRef(Path.data(), Path.size()))) {
4907330f729Sjoerg FS->makeAbsolute(Path);
4917330f729Sjoerg Changed = true;
4927330f729Sjoerg }
4937330f729Sjoerg
4947330f729Sjoerg return Changed;
4957330f729Sjoerg }
4967330f729Sjoerg
fillRealPathName(FileEntry * UFE,llvm::StringRef FileName)4977330f729Sjoerg void FileManager::fillRealPathName(FileEntry *UFE, llvm::StringRef FileName) {
4987330f729Sjoerg llvm::SmallString<128> AbsPath(FileName);
4997330f729Sjoerg // This is not the same as `VFS::getRealPath()`, which resolves symlinks
5007330f729Sjoerg // but can be very expensive on real file systems.
5017330f729Sjoerg // FIXME: the semantic of RealPathName is unclear, and the name might be
5027330f729Sjoerg // misleading. We need to clean up the interface here.
5037330f729Sjoerg makeAbsolutePath(AbsPath);
5047330f729Sjoerg llvm::sys::path::remove_dots(AbsPath, /*remove_dot_dot=*/true);
505*e038c9c4Sjoerg UFE->RealPathName = std::string(AbsPath.str());
5067330f729Sjoerg }
5077330f729Sjoerg
5087330f729Sjoerg llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
getBufferForFile(const FileEntry * Entry,bool isVolatile,bool RequiresNullTerminator)509*e038c9c4Sjoerg FileManager::getBufferForFile(const FileEntry *Entry, bool isVolatile,
510*e038c9c4Sjoerg bool RequiresNullTerminator) {
511*e038c9c4Sjoerg // If the content is living on the file entry, return a reference to it.
512*e038c9c4Sjoerg if (Entry->Content)
513*e038c9c4Sjoerg return llvm::MemoryBuffer::getMemBuffer(Entry->Content->getMemBufferRef());
514*e038c9c4Sjoerg
5157330f729Sjoerg uint64_t FileSize = Entry->getSize();
5167330f729Sjoerg // If there's a high enough chance that the file have changed since we
5177330f729Sjoerg // got its size, force a stat before opening it.
518*e038c9c4Sjoerg if (isVolatile || Entry->isNamedPipe())
5197330f729Sjoerg FileSize = -1;
5207330f729Sjoerg
5217330f729Sjoerg StringRef Filename = Entry->getName();
5227330f729Sjoerg // If the file is already open, use the open file descriptor.
5237330f729Sjoerg if (Entry->File) {
524*e038c9c4Sjoerg auto Result = Entry->File->getBuffer(Filename, FileSize,
525*e038c9c4Sjoerg RequiresNullTerminator, isVolatile);
5267330f729Sjoerg Entry->closeFile();
5277330f729Sjoerg return Result;
5287330f729Sjoerg }
5297330f729Sjoerg
5307330f729Sjoerg // Otherwise, open the file.
531*e038c9c4Sjoerg return getBufferForFileImpl(Filename, FileSize, isVolatile,
532*e038c9c4Sjoerg RequiresNullTerminator);
5337330f729Sjoerg }
5347330f729Sjoerg
5357330f729Sjoerg llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
getBufferForFileImpl(StringRef Filename,int64_t FileSize,bool isVolatile,bool RequiresNullTerminator)5367330f729Sjoerg FileManager::getBufferForFileImpl(StringRef Filename, int64_t FileSize,
537*e038c9c4Sjoerg bool isVolatile,
538*e038c9c4Sjoerg bool RequiresNullTerminator) {
5397330f729Sjoerg if (FileSystemOpts.WorkingDir.empty())
540*e038c9c4Sjoerg return FS->getBufferForFile(Filename, FileSize, RequiresNullTerminator,
541*e038c9c4Sjoerg isVolatile);
5427330f729Sjoerg
5437330f729Sjoerg SmallString<128> FilePath(Filename);
5447330f729Sjoerg FixupRelativePath(FilePath);
545*e038c9c4Sjoerg return FS->getBufferForFile(FilePath, FileSize, RequiresNullTerminator,
546*e038c9c4Sjoerg isVolatile);
5477330f729Sjoerg }
5487330f729Sjoerg
5497330f729Sjoerg /// getStatValue - Get the 'stat' information for the specified path,
5507330f729Sjoerg /// using the cache to accelerate it if possible. This returns true
5517330f729Sjoerg /// if the path points to a virtual file or does not exist, or returns
5527330f729Sjoerg /// false if it's an existent real file. If FileDescriptor is NULL,
5537330f729Sjoerg /// do directory look-up instead of file look-up.
5547330f729Sjoerg std::error_code
getStatValue(StringRef Path,llvm::vfs::Status & Status,bool isFile,std::unique_ptr<llvm::vfs::File> * F)5557330f729Sjoerg FileManager::getStatValue(StringRef Path, llvm::vfs::Status &Status,
5567330f729Sjoerg bool isFile, std::unique_ptr<llvm::vfs::File> *F) {
5577330f729Sjoerg // FIXME: FileSystemOpts shouldn't be passed in here, all paths should be
5587330f729Sjoerg // absolute!
5597330f729Sjoerg if (FileSystemOpts.WorkingDir.empty())
5607330f729Sjoerg return FileSystemStatCache::get(Path, Status, isFile, F,
5617330f729Sjoerg StatCache.get(), *FS);
5627330f729Sjoerg
5637330f729Sjoerg SmallString<128> FilePath(Path);
5647330f729Sjoerg FixupRelativePath(FilePath);
5657330f729Sjoerg
5667330f729Sjoerg return FileSystemStatCache::get(FilePath.c_str(), Status, isFile, F,
5677330f729Sjoerg StatCache.get(), *FS);
5687330f729Sjoerg }
5697330f729Sjoerg
5707330f729Sjoerg std::error_code
getNoncachedStatValue(StringRef Path,llvm::vfs::Status & Result)5717330f729Sjoerg FileManager::getNoncachedStatValue(StringRef Path,
5727330f729Sjoerg llvm::vfs::Status &Result) {
5737330f729Sjoerg SmallString<128> FilePath(Path);
5747330f729Sjoerg FixupRelativePath(FilePath);
5757330f729Sjoerg
5767330f729Sjoerg llvm::ErrorOr<llvm::vfs::Status> S = FS->status(FilePath.c_str());
5777330f729Sjoerg if (!S)
5787330f729Sjoerg return S.getError();
5797330f729Sjoerg Result = *S;
5807330f729Sjoerg return std::error_code();
5817330f729Sjoerg }
5827330f729Sjoerg
GetUniqueIDMapping(SmallVectorImpl<const FileEntry * > & UIDToFiles) const5837330f729Sjoerg void FileManager::GetUniqueIDMapping(
5847330f729Sjoerg SmallVectorImpl<const FileEntry *> &UIDToFiles) const {
5857330f729Sjoerg UIDToFiles.clear();
5867330f729Sjoerg UIDToFiles.resize(NextFileUID);
5877330f729Sjoerg
5887330f729Sjoerg // Map file entries
589*e038c9c4Sjoerg for (llvm::StringMap<llvm::ErrorOr<FileEntryRef::MapValue>,
5907330f729Sjoerg llvm::BumpPtrAllocator>::const_iterator
5917330f729Sjoerg FE = SeenFileEntries.begin(),
5927330f729Sjoerg FEEnd = SeenFileEntries.end();
5937330f729Sjoerg FE != FEEnd; ++FE)
594*e038c9c4Sjoerg if (llvm::ErrorOr<FileEntryRef::MapValue> Entry = FE->getValue()) {
595*e038c9c4Sjoerg if (const auto *FE = Entry->V.dyn_cast<FileEntry *>())
5967330f729Sjoerg UIDToFiles[FE->getUID()] = FE;
5977330f729Sjoerg }
5987330f729Sjoerg
5997330f729Sjoerg // Map virtual file entries
6007330f729Sjoerg for (const auto &VFE : VirtualFileEntries)
6017330f729Sjoerg UIDToFiles[VFE->getUID()] = VFE.get();
6027330f729Sjoerg }
6037330f729Sjoerg
getCanonicalName(const DirectoryEntry * Dir)6047330f729Sjoerg StringRef FileManager::getCanonicalName(const DirectoryEntry *Dir) {
605*e038c9c4Sjoerg llvm::DenseMap<const void *, llvm::StringRef>::iterator Known
606*e038c9c4Sjoerg = CanonicalNames.find(Dir);
607*e038c9c4Sjoerg if (Known != CanonicalNames.end())
6087330f729Sjoerg return Known->second;
6097330f729Sjoerg
6107330f729Sjoerg StringRef CanonicalName(Dir->getName());
6117330f729Sjoerg
6127330f729Sjoerg SmallString<4096> CanonicalNameBuf;
6137330f729Sjoerg if (!FS->getRealPath(Dir->getName(), CanonicalNameBuf))
6147330f729Sjoerg CanonicalName = StringRef(CanonicalNameBuf).copy(CanonicalNameStorage);
6157330f729Sjoerg
616*e038c9c4Sjoerg CanonicalNames.insert({Dir, CanonicalName});
617*e038c9c4Sjoerg return CanonicalName;
618*e038c9c4Sjoerg }
619*e038c9c4Sjoerg
getCanonicalName(const FileEntry * File)620*e038c9c4Sjoerg StringRef FileManager::getCanonicalName(const FileEntry *File) {
621*e038c9c4Sjoerg llvm::DenseMap<const void *, llvm::StringRef>::iterator Known
622*e038c9c4Sjoerg = CanonicalNames.find(File);
623*e038c9c4Sjoerg if (Known != CanonicalNames.end())
624*e038c9c4Sjoerg return Known->second;
625*e038c9c4Sjoerg
626*e038c9c4Sjoerg StringRef CanonicalName(File->getName());
627*e038c9c4Sjoerg
628*e038c9c4Sjoerg SmallString<4096> CanonicalNameBuf;
629*e038c9c4Sjoerg if (!FS->getRealPath(File->getName(), CanonicalNameBuf))
630*e038c9c4Sjoerg CanonicalName = StringRef(CanonicalNameBuf).copy(CanonicalNameStorage);
631*e038c9c4Sjoerg
632*e038c9c4Sjoerg CanonicalNames.insert({File, CanonicalName});
6337330f729Sjoerg return CanonicalName;
6347330f729Sjoerg }
6357330f729Sjoerg
PrintStats() const6367330f729Sjoerg void FileManager::PrintStats() const {
6377330f729Sjoerg llvm::errs() << "\n*** File Manager Stats:\n";
6387330f729Sjoerg llvm::errs() << UniqueRealFiles.size() << " real files found, "
6397330f729Sjoerg << UniqueRealDirs.size() << " real dirs found.\n";
6407330f729Sjoerg llvm::errs() << VirtualFileEntries.size() << " virtual files found, "
6417330f729Sjoerg << VirtualDirectoryEntries.size() << " virtual dirs found.\n";
6427330f729Sjoerg llvm::errs() << NumDirLookups << " dir lookups, "
6437330f729Sjoerg << NumDirCacheMisses << " dir cache misses.\n";
6447330f729Sjoerg llvm::errs() << NumFileLookups << " file lookups, "
6457330f729Sjoerg << NumFileCacheMisses << " file cache misses.\n";
6467330f729Sjoerg
6477330f729Sjoerg //llvm::errs() << PagesMapped << BytesOfPagesMapped << FSLookups;
6487330f729Sjoerg }
649