xref: /netbsd-src/external/apache2/llvm/dist/clang/lib/Basic/FileManager.cpp (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
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