12754fe60SDimitry Andric //===--- FileManager.cpp - File System Probing and Caching ----------------===//
2f22ef01cSRoman Divacky //
3f22ef01cSRoman Divacky //                     The LLVM Compiler Infrastructure
4f22ef01cSRoman Divacky //
5f22ef01cSRoman Divacky // This file is distributed under the University of Illinois Open Source
6f22ef01cSRoman Divacky // License. See LICENSE.TXT for details.
7f22ef01cSRoman Divacky //
8f22ef01cSRoman Divacky //===----------------------------------------------------------------------===//
9f22ef01cSRoman Divacky //
10f22ef01cSRoman Divacky //  This file implements the FileManager interface.
11f22ef01cSRoman Divacky //
12f22ef01cSRoman Divacky //===----------------------------------------------------------------------===//
13f22ef01cSRoman Divacky //
14f22ef01cSRoman Divacky // TODO: This should index all interesting directories with dirent calls.
15f22ef01cSRoman Divacky //  getdirentries ?
16f22ef01cSRoman Divacky //  opendir/readdir_r/closedir ?
17f22ef01cSRoman Divacky //
18f22ef01cSRoman Divacky //===----------------------------------------------------------------------===//
19f22ef01cSRoman Divacky 
20f22ef01cSRoman Divacky #include "clang/Basic/FileManager.h"
212754fe60SDimitry Andric #include "clang/Basic/FileSystemStatCache.h"
22f22ef01cSRoman Divacky #include "llvm/ADT/SmallString.h"
23139f7f9bSDimitry Andric #include "llvm/Config/llvm-config.h"
240623d748SDimitry Andric #include "llvm/ADT/STLExtras.h"
252754fe60SDimitry Andric #include "llvm/Support/FileSystem.h"
262754fe60SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
272754fe60SDimitry Andric #include "llvm/Support/Path.h"
28139f7f9bSDimitry Andric #include "llvm/Support/raw_ostream.h"
2944290647SDimitry Andric #include <algorithm>
3044290647SDimitry Andric #include <cassert>
3144290647SDimitry Andric #include <climits>
3244290647SDimitry Andric #include <cstdint>
3344290647SDimitry Andric #include <cstdlib>
34f22ef01cSRoman Divacky #include <string>
3544290647SDimitry Andric #include <utility>
362754fe60SDimitry Andric 
37f22ef01cSRoman Divacky using namespace clang;
38f22ef01cSRoman Divacky 
39f22ef01cSRoman Divacky /// NON_EXISTENT_DIR - A special value distinct from null that is used to
40f22ef01cSRoman Divacky /// represent a dir name that doesn't exist on the disk.
41f22ef01cSRoman Divacky #define NON_EXISTENT_DIR reinterpret_cast<DirectoryEntry*>((intptr_t)-1)
42f22ef01cSRoman Divacky 
432754fe60SDimitry Andric /// NON_EXISTENT_FILE - A special value distinct from null that is used to
442754fe60SDimitry Andric /// represent a filename that doesn't exist on the disk.
452754fe60SDimitry Andric #define NON_EXISTENT_FILE reinterpret_cast<FileEntry*>((intptr_t)-1)
462754fe60SDimitry Andric 
47f22ef01cSRoman Divacky //===----------------------------------------------------------------------===//
48f22ef01cSRoman Divacky // Common logic.
49f22ef01cSRoman Divacky //===----------------------------------------------------------------------===//
50f22ef01cSRoman Divacky 
FileManager(const FileSystemOptions & FSO,IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)5159d1ed5bSDimitry Andric FileManager::FileManager(const FileSystemOptions &FSO,
52*b5893f02SDimitry Andric                          IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)
5320e90f04SDimitry Andric     : FS(std::move(FS)), FileSystemOpts(FSO), SeenDirEntries(64),
5420e90f04SDimitry Andric       SeenFileEntries(64), NextFileUID(0) {
55f22ef01cSRoman Divacky   NumDirLookups = NumFileLookups = 0;
56f22ef01cSRoman Divacky   NumDirCacheMisses = NumFileCacheMisses = 0;
5759d1ed5bSDimitry Andric 
5859d1ed5bSDimitry Andric   // If the caller doesn't provide a virtual file system, just grab the real
5959d1ed5bSDimitry Andric   // file system.
6020e90f04SDimitry Andric   if (!this->FS)
61*b5893f02SDimitry Andric     this->FS = llvm::vfs::getRealFileSystem();
62f22ef01cSRoman Divacky }
63f22ef01cSRoman Divacky 
640623d748SDimitry Andric FileManager::~FileManager() = default;
65f22ef01cSRoman Divacky 
setStatCache(std::unique_ptr<FileSystemStatCache> statCache)66*b5893f02SDimitry Andric void FileManager::setStatCache(std::unique_ptr<FileSystemStatCache> statCache) {
67f22ef01cSRoman Divacky   assert(statCache && "No stat cache provided?");
6839d628a0SDimitry Andric   StatCache = std::move(statCache);
69f22ef01cSRoman Divacky }
70f22ef01cSRoman Divacky 
clearStatCache()71*b5893f02SDimitry Andric void FileManager::clearStatCache() { StatCache.reset(); }
727ae0e2c9SDimitry Andric 
734ba319b5SDimitry Andric /// Retrieve the directory that the given file name resides in.
742754fe60SDimitry Andric /// Filename can point to either a real file or a virtual file.
getDirectoryFromFile(FileManager & FileMgr,StringRef Filename,bool CacheFailure)75f22ef01cSRoman Divacky static const DirectoryEntry *getDirectoryFromFile(FileManager &FileMgr,
766122f3e6SDimitry Andric                                                   StringRef Filename,
776122f3e6SDimitry Andric                                                   bool CacheFailure) {
782754fe60SDimitry Andric   if (Filename.empty())
7959d1ed5bSDimitry Andric     return nullptr;
80f22ef01cSRoman Divacky 
812754fe60SDimitry Andric   if (llvm::sys::path::is_separator(Filename[Filename.size() - 1]))
8259d1ed5bSDimitry Andric     return nullptr; // If Filename is a directory.
832754fe60SDimitry Andric 
846122f3e6SDimitry Andric   StringRef DirName = llvm::sys::path::parent_path(Filename);
85f22ef01cSRoman Divacky   // Use the current directory if file has no path component.
862754fe60SDimitry Andric   if (DirName.empty())
872754fe60SDimitry Andric     DirName = ".";
882754fe60SDimitry Andric 
896122f3e6SDimitry Andric   return FileMgr.getDirectory(DirName, CacheFailure);
90f22ef01cSRoman Divacky }
91f22ef01cSRoman Divacky 
922754fe60SDimitry Andric /// Add all ancestors of the given path (pointing to either a file or
932754fe60SDimitry Andric /// a directory) as virtual directories.
addAncestorsAsVirtualDirs(StringRef Path)946122f3e6SDimitry Andric void FileManager::addAncestorsAsVirtualDirs(StringRef Path) {
956122f3e6SDimitry Andric   StringRef DirName = llvm::sys::path::parent_path(Path);
962754fe60SDimitry Andric   if (DirName.empty())
97e7145dcbSDimitry Andric     DirName = ".";
982754fe60SDimitry Andric 
9939d628a0SDimitry Andric   auto &NamedDirEnt =
10039d628a0SDimitry Andric       *SeenDirEntries.insert(std::make_pair(DirName, nullptr)).first;
1012754fe60SDimitry Andric 
1022754fe60SDimitry Andric   // When caching a virtual directory, we always cache its ancestors
1032754fe60SDimitry Andric   // at the same time.  Therefore, if DirName is already in the cache,
1042754fe60SDimitry Andric   // we don't need to recurse as its ancestors must also already be in
1052754fe60SDimitry Andric   // the cache.
1060623d748SDimitry Andric   if (NamedDirEnt.second && NamedDirEnt.second != NON_EXISTENT_DIR)
1072754fe60SDimitry Andric     return;
1082754fe60SDimitry Andric 
1092754fe60SDimitry Andric   // Add the virtual directory to the cache.
1100623d748SDimitry Andric   auto UDE = llvm::make_unique<DirectoryEntry>();
11144290647SDimitry Andric   UDE->Name = NamedDirEnt.first();
1120623d748SDimitry Andric   NamedDirEnt.second = UDE.get();
1130623d748SDimitry Andric   VirtualDirectoryEntries.push_back(std::move(UDE));
1142754fe60SDimitry Andric 
1152754fe60SDimitry Andric   // Recursively add the other ancestors.
1162754fe60SDimitry Andric   addAncestorsAsVirtualDirs(DirName);
1172754fe60SDimitry Andric }
1182754fe60SDimitry Andric 
getDirectory(StringRef DirName,bool CacheFailure)1196122f3e6SDimitry Andric const DirectoryEntry *FileManager::getDirectory(StringRef DirName,
1206122f3e6SDimitry Andric                                                 bool CacheFailure) {
1217ae0e2c9SDimitry Andric   // stat doesn't like trailing separators except for root directory.
122dff0c46cSDimitry Andric   // At least, on Win32 MSVCRT, stat() cannot strip trailing '/'.
123dff0c46cSDimitry Andric   // (though it can strip '\\')
1247ae0e2c9SDimitry Andric   if (DirName.size() > 1 &&
1257ae0e2c9SDimitry Andric       DirName != llvm::sys::path::root_path(DirName) &&
1267ae0e2c9SDimitry Andric       llvm::sys::path::is_separator(DirName.back()))
127dff0c46cSDimitry Andric     DirName = DirName.substr(0, DirName.size()-1);
1284ba319b5SDimitry Andric #ifdef _WIN32
129f785676fSDimitry Andric   // Fixing a problem with "clang C:test.c" on Windows.
130f785676fSDimitry Andric   // Stat("C:") does not recognize "C:" as a valid directory
131f785676fSDimitry Andric   std::string DirNameStr;
132f785676fSDimitry Andric   if (DirName.size() > 1 && DirName.back() == ':' &&
133f785676fSDimitry Andric       DirName.equals_lower(llvm::sys::path::root_name(DirName))) {
134f785676fSDimitry Andric     DirNameStr = DirName.str() + '.';
135f785676fSDimitry Andric     DirName = DirNameStr;
136f785676fSDimitry Andric   }
137f785676fSDimitry Andric #endif
138dff0c46cSDimitry Andric 
139f22ef01cSRoman Divacky   ++NumDirLookups;
14039d628a0SDimitry Andric   auto &NamedDirEnt =
14139d628a0SDimitry Andric       *SeenDirEntries.insert(std::make_pair(DirName, nullptr)).first;
142f22ef01cSRoman Divacky 
1432754fe60SDimitry Andric   // See if there was already an entry in the map.  Note that the map
1442754fe60SDimitry Andric   // contains both virtual and real directories.
14539d628a0SDimitry Andric   if (NamedDirEnt.second)
14639d628a0SDimitry Andric     return NamedDirEnt.second == NON_EXISTENT_DIR ? nullptr
14739d628a0SDimitry Andric                                                   : NamedDirEnt.second;
148f22ef01cSRoman Divacky 
149f22ef01cSRoman Divacky   ++NumDirCacheMisses;
150f22ef01cSRoman Divacky 
151f22ef01cSRoman Divacky   // By default, initialize it to invalid.
15239d628a0SDimitry Andric   NamedDirEnt.second = NON_EXISTENT_DIR;
153f22ef01cSRoman Divacky 
154f22ef01cSRoman Divacky   // Get the null-terminated directory name as stored as the key of the
1552754fe60SDimitry Andric   // SeenDirEntries map.
15644290647SDimitry Andric   StringRef InterndDirName = NamedDirEnt.first();
157f22ef01cSRoman Divacky 
158f22ef01cSRoman Divacky   // Check to see if the directory exists.
159f785676fSDimitry Andric   FileData Data;
16059d1ed5bSDimitry Andric   if (getStatValue(InterndDirName, Data, false, nullptr /*directory lookup*/)) {
1612754fe60SDimitry Andric     // There's no real directory at the given path.
1626122f3e6SDimitry Andric     if (!CacheFailure)
1636122f3e6SDimitry Andric       SeenDirEntries.erase(DirName);
16459d1ed5bSDimitry Andric     return nullptr;
1652754fe60SDimitry Andric   }
166f22ef01cSRoman Divacky 
1672754fe60SDimitry Andric   // It exists.  See if we have already opened a directory with the
1682754fe60SDimitry Andric   // same inode (this occurs on Unix-like systems when one dir is
1692754fe60SDimitry Andric   // symlinked to another, for example) or the same path (on
1702754fe60SDimitry Andric   // Windows).
17159d1ed5bSDimitry Andric   DirectoryEntry &UDE = UniqueRealDirs[Data.UniqueID];
172f22ef01cSRoman Divacky 
17339d628a0SDimitry Andric   NamedDirEnt.second = &UDE;
17444290647SDimitry Andric   if (UDE.getName().empty()) {
1752754fe60SDimitry Andric     // We don't have this directory yet, add it.  We use the string
1762754fe60SDimitry Andric     // key from the SeenDirEntries map as the string.
177f22ef01cSRoman Divacky     UDE.Name  = InterndDirName;
1782754fe60SDimitry Andric   }
1792754fe60SDimitry Andric 
180f22ef01cSRoman Divacky   return &UDE;
181f22ef01cSRoman Divacky }
182f22ef01cSRoman Divacky 
getFile(StringRef Filename,bool openFile,bool CacheFailure)1836122f3e6SDimitry Andric const FileEntry *FileManager::getFile(StringRef Filename, bool openFile,
1846122f3e6SDimitry Andric                                       bool CacheFailure) {
185f22ef01cSRoman Divacky   ++NumFileLookups;
186f22ef01cSRoman Divacky 
187f22ef01cSRoman Divacky   // See if there is already an entry in the map.
18839d628a0SDimitry Andric   auto &NamedFileEnt =
18939d628a0SDimitry Andric       *SeenFileEntries.insert(std::make_pair(Filename, nullptr)).first;
190f22ef01cSRoman Divacky 
191f22ef01cSRoman Divacky   // See if there is already an entry in the map.
19239d628a0SDimitry Andric   if (NamedFileEnt.second)
19339d628a0SDimitry Andric     return NamedFileEnt.second == NON_EXISTENT_FILE ? nullptr
19439d628a0SDimitry Andric                                                     : NamedFileEnt.second;
195f22ef01cSRoman Divacky 
196f22ef01cSRoman Divacky   ++NumFileCacheMisses;
197f22ef01cSRoman Divacky 
198f22ef01cSRoman Divacky   // By default, initialize it to invalid.
19939d628a0SDimitry Andric   NamedFileEnt.second = NON_EXISTENT_FILE;
200f22ef01cSRoman Divacky 
201f22ef01cSRoman Divacky   // Get the null-terminated file name as stored as the key of the
2022754fe60SDimitry Andric   // SeenFileEntries map.
20344290647SDimitry Andric   StringRef InterndFileName = NamedFileEnt.first();
204f22ef01cSRoman Divacky 
2052754fe60SDimitry Andric   // Look up the directory for the file.  When looking up something like
2062754fe60SDimitry Andric   // sys/foo.h we'll discover all of the search directories that have a 'sys'
2072754fe60SDimitry Andric   // subdirectory.  This will let us avoid having to waste time on known-to-fail
2082754fe60SDimitry Andric   // searches when we go to find sys/bar.h, because all the search directories
2092754fe60SDimitry Andric   // without a 'sys' subdir will get a cached failure result.
2106122f3e6SDimitry Andric   const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename,
2116122f3e6SDimitry Andric                                                        CacheFailure);
21259d1ed5bSDimitry Andric   if (DirInfo == nullptr) { // Directory doesn't exist, file can't exist.
2136122f3e6SDimitry Andric     if (!CacheFailure)
2146122f3e6SDimitry Andric       SeenFileEntries.erase(Filename);
2156122f3e6SDimitry Andric 
21659d1ed5bSDimitry Andric     return nullptr;
2176122f3e6SDimitry Andric   }
218f22ef01cSRoman Divacky 
219f22ef01cSRoman Divacky   // FIXME: Use the directory info to prune this, before doing the stat syscall.
220f22ef01cSRoman Divacky   // FIXME: This will reduce the # syscalls.
221f22ef01cSRoman Divacky 
222f22ef01cSRoman Divacky   // Nope, there isn't.  Check to see if the file exists.
223*b5893f02SDimitry Andric   std::unique_ptr<llvm::vfs::File> F;
224f785676fSDimitry Andric   FileData Data;
22559d1ed5bSDimitry Andric   if (getStatValue(InterndFileName, Data, true, openFile ? &F : nullptr)) {
2262754fe60SDimitry Andric     // There's no real file at the given path.
2276122f3e6SDimitry Andric     if (!CacheFailure)
2286122f3e6SDimitry Andric       SeenFileEntries.erase(Filename);
2296122f3e6SDimitry Andric 
23059d1ed5bSDimitry Andric     return nullptr;
231f22ef01cSRoman Divacky   }
232f22ef01cSRoman Divacky 
23359d1ed5bSDimitry Andric   assert((openFile || !F) && "undesired open file");
2343b0f4066SDimitry Andric 
235f22ef01cSRoman Divacky   // It exists.  See if we have already opened a file with the same inode.
236f22ef01cSRoman Divacky   // This occurs when one dir is symlinked to another, for example.
23759d1ed5bSDimitry Andric   FileEntry &UFE = UniqueRealFiles[Data.UniqueID];
238f22ef01cSRoman Divacky 
23939d628a0SDimitry Andric   NamedFileEnt.second = &UFE;
24039d628a0SDimitry Andric 
24139d628a0SDimitry Andric   // If the name returned by getStatValue is different than Filename, re-intern
24239d628a0SDimitry Andric   // the name.
24339d628a0SDimitry Andric   if (Data.Name != Filename) {
24439d628a0SDimitry Andric     auto &NamedFileEnt =
24539d628a0SDimitry Andric         *SeenFileEntries.insert(std::make_pair(Data.Name, nullptr)).first;
24639d628a0SDimitry Andric     if (!NamedFileEnt.second)
24739d628a0SDimitry Andric       NamedFileEnt.second = &UFE;
24839d628a0SDimitry Andric     else
24939d628a0SDimitry Andric       assert(NamedFileEnt.second == &UFE &&
25039d628a0SDimitry Andric              "filename from getStatValue() refers to wrong file");
25139d628a0SDimitry Andric     InterndFileName = NamedFileEnt.first().data();
25239d628a0SDimitry Andric   }
25339d628a0SDimitry Andric 
25459d1ed5bSDimitry Andric   if (UFE.isValid()) { // Already have an entry with this inode, return it.
25559d1ed5bSDimitry Andric 
25659d1ed5bSDimitry Andric     // FIXME: this hack ensures that if we look up a file by a virtual path in
25759d1ed5bSDimitry Andric     // the VFS that the getDir() will have the virtual path, even if we found
25859d1ed5bSDimitry Andric     // the file by a 'real' path first. This is required in order to find a
25959d1ed5bSDimitry Andric     // module's structure when its headers/module map are mapped in the VFS.
26059d1ed5bSDimitry Andric     // We should remove this as soon as we can properly support a file having
26159d1ed5bSDimitry Andric     // multiple names.
26259d1ed5bSDimitry Andric     if (DirInfo != UFE.Dir && Data.IsVFSMapped)
26359d1ed5bSDimitry Andric       UFE.Dir = DirInfo;
2642754fe60SDimitry Andric 
26539d628a0SDimitry Andric     // Always update the name to use the last name by which a file was accessed.
26639d628a0SDimitry Andric     // FIXME: Neither this nor always using the first name is correct; we want
26739d628a0SDimitry Andric     // to switch towards a design where we return a FileName object that
26839d628a0SDimitry Andric     // encapsulates both the name by which the file was accessed and the
26939d628a0SDimitry Andric     // corresponding FileEntry.
27039d628a0SDimitry Andric     UFE.Name = InterndFileName;
27139d628a0SDimitry Andric 
272f22ef01cSRoman Divacky     return &UFE;
2732754fe60SDimitry Andric   }
274f22ef01cSRoman Divacky 
27559d1ed5bSDimitry Andric   // Otherwise, we don't have this file yet, add it.
27639d628a0SDimitry Andric   UFE.Name    = InterndFileName;
277f785676fSDimitry Andric   UFE.Size = Data.Size;
278f785676fSDimitry Andric   UFE.ModTime = Data.ModTime;
279f22ef01cSRoman Divacky   UFE.Dir     = DirInfo;
280f22ef01cSRoman Divacky   UFE.UID     = NextFileUID++;
28159d1ed5bSDimitry Andric   UFE.UniqueID = Data.UniqueID;
28259d1ed5bSDimitry Andric   UFE.IsNamedPipe = Data.IsNamedPipe;
28359d1ed5bSDimitry Andric   UFE.InPCH = Data.InPCH;
28459d1ed5bSDimitry Andric   UFE.File = std::move(F);
28559d1ed5bSDimitry Andric   UFE.IsValid = true;
286*b5893f02SDimitry Andric 
287*b5893f02SDimitry Andric   if (UFE.File) {
288*b5893f02SDimitry Andric     if (auto PathName = UFE.File->getName())
289*b5893f02SDimitry Andric       fillRealPathName(&UFE, *PathName);
290*b5893f02SDimitry Andric   }
291f22ef01cSRoman Divacky   return &UFE;
292f22ef01cSRoman Divacky }
293f22ef01cSRoman Divacky 
294f22ef01cSRoman Divacky const FileEntry *
getVirtualFile(StringRef Filename,off_t Size,time_t ModificationTime)2956122f3e6SDimitry Andric FileManager::getVirtualFile(StringRef Filename, off_t Size,
296ffd1746dSEd Schouten                             time_t ModificationTime) {
297f22ef01cSRoman Divacky   ++NumFileLookups;
298f22ef01cSRoman Divacky 
299f22ef01cSRoman Divacky   // See if there is already an entry in the map.
30039d628a0SDimitry Andric   auto &NamedFileEnt =
30139d628a0SDimitry Andric       *SeenFileEntries.insert(std::make_pair(Filename, nullptr)).first;
302f22ef01cSRoman Divacky 
303f22ef01cSRoman Divacky   // See if there is already an entry in the map.
30439d628a0SDimitry Andric   if (NamedFileEnt.second && NamedFileEnt.second != NON_EXISTENT_FILE)
30539d628a0SDimitry Andric     return NamedFileEnt.second;
306f22ef01cSRoman Divacky 
307f22ef01cSRoman Divacky   ++NumFileCacheMisses;
308f22ef01cSRoman Divacky 
309f22ef01cSRoman Divacky   // By default, initialize it to invalid.
31039d628a0SDimitry Andric   NamedFileEnt.second = NON_EXISTENT_FILE;
311f22ef01cSRoman Divacky 
3122754fe60SDimitry Andric   addAncestorsAsVirtualDirs(Filename);
31359d1ed5bSDimitry Andric   FileEntry *UFE = nullptr;
314f22ef01cSRoman Divacky 
3152754fe60SDimitry Andric   // Now that all ancestors of Filename are in the cache, the
3162754fe60SDimitry Andric   // following call is guaranteed to find the DirectoryEntry from the
3172754fe60SDimitry Andric   // cache.
3186122f3e6SDimitry Andric   const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename,
3196122f3e6SDimitry Andric                                                        /*CacheFailure=*/true);
3202754fe60SDimitry Andric   assert(DirInfo &&
3212754fe60SDimitry Andric          "The directory of a virtual file should already be in the cache.");
3222754fe60SDimitry Andric 
3232754fe60SDimitry Andric   // Check to see if the file exists. If so, drop the virtual file
324f785676fSDimitry Andric   FileData Data;
32539d628a0SDimitry Andric   const char *InterndFileName = NamedFileEnt.first().data();
32659d1ed5bSDimitry Andric   if (getStatValue(InterndFileName, Data, true, nullptr) == 0) {
327f785676fSDimitry Andric     Data.Size = Size;
328f785676fSDimitry Andric     Data.ModTime = ModificationTime;
32959d1ed5bSDimitry Andric     UFE = &UniqueRealFiles[Data.UniqueID];
3302754fe60SDimitry Andric 
33139d628a0SDimitry Andric     NamedFileEnt.second = UFE;
332f22ef01cSRoman Divacky 
3332754fe60SDimitry Andric     // If we had already opened this file, close it now so we don't
3342754fe60SDimitry Andric     // leak the descriptor. We're not going to use the file
3352754fe60SDimitry Andric     // descriptor anyway, since this is a virtual file.
33659d1ed5bSDimitry Andric     if (UFE->File)
33759d1ed5bSDimitry Andric       UFE->closeFile();
3382754fe60SDimitry Andric 
3392754fe60SDimitry Andric     // If we already have an entry with this inode, return it.
34059d1ed5bSDimitry Andric     if (UFE->isValid())
3412754fe60SDimitry Andric       return UFE;
34259d1ed5bSDimitry Andric 
34359d1ed5bSDimitry Andric     UFE->UniqueID = Data.UniqueID;
34459d1ed5bSDimitry Andric     UFE->IsNamedPipe = Data.IsNamedPipe;
34559d1ed5bSDimitry Andric     UFE->InPCH = Data.InPCH;
346*b5893f02SDimitry Andric     fillRealPathName(UFE, Data.Name);
3472754fe60SDimitry Andric   }
3482754fe60SDimitry Andric 
3492754fe60SDimitry Andric   if (!UFE) {
3500623d748SDimitry Andric     VirtualFileEntries.push_back(llvm::make_unique<FileEntry>());
3510623d748SDimitry Andric     UFE = VirtualFileEntries.back().get();
35239d628a0SDimitry Andric     NamedFileEnt.second = UFE;
3532754fe60SDimitry Andric   }
3542754fe60SDimitry Andric 
3552754fe60SDimitry Andric   UFE->Name    = InterndFileName;
356f22ef01cSRoman Divacky   UFE->Size    = Size;
357f22ef01cSRoman Divacky   UFE->ModTime = ModificationTime;
358f22ef01cSRoman Divacky   UFE->Dir     = DirInfo;
359f22ef01cSRoman Divacky   UFE->UID     = NextFileUID++;
36020e90f04SDimitry Andric   UFE->IsValid = true;
36159d1ed5bSDimitry Andric   UFE->File.reset();
362f22ef01cSRoman Divacky   return UFE;
363f22ef01cSRoman Divacky }
364f22ef01cSRoman Divacky 
FixupRelativePath(SmallVectorImpl<char> & path) const3650623d748SDimitry Andric bool FileManager::FixupRelativePath(SmallVectorImpl<char> &path) const {
3666122f3e6SDimitry Andric   StringRef pathRef(path.data(), path.size());
3673b0f4066SDimitry Andric 
3683b0f4066SDimitry Andric   if (FileSystemOpts.WorkingDir.empty()
3693b0f4066SDimitry Andric       || llvm::sys::path::is_absolute(pathRef))
3700623d748SDimitry Andric     return false;
3712754fe60SDimitry Andric 
372dff0c46cSDimitry Andric   SmallString<128> NewPath(FileSystemOpts.WorkingDir);
3733b0f4066SDimitry Andric   llvm::sys::path::append(NewPath, pathRef);
3742754fe60SDimitry Andric   path = NewPath;
3750623d748SDimitry Andric   return true;
3760623d748SDimitry Andric }
3770623d748SDimitry Andric 
makeAbsolutePath(SmallVectorImpl<char> & Path) const3780623d748SDimitry Andric bool FileManager::makeAbsolutePath(SmallVectorImpl<char> &Path) const {
3790623d748SDimitry Andric   bool Changed = FixupRelativePath(Path);
3800623d748SDimitry Andric 
3810623d748SDimitry Andric   if (!llvm::sys::path::is_absolute(StringRef(Path.data(), Path.size()))) {
3829a199699SDimitry Andric     FS->makeAbsolute(Path);
3830623d748SDimitry Andric     Changed = true;
3840623d748SDimitry Andric   }
3850623d748SDimitry Andric 
3860623d748SDimitry Andric   return Changed;
3872754fe60SDimitry Andric }
3882754fe60SDimitry Andric 
fillRealPathName(FileEntry * UFE,llvm::StringRef FileName)389*b5893f02SDimitry Andric void FileManager::fillRealPathName(FileEntry *UFE, llvm::StringRef FileName) {
390*b5893f02SDimitry Andric   llvm::SmallString<128> AbsPath(FileName);
391*b5893f02SDimitry Andric   // This is not the same as `VFS::getRealPath()`, which resolves symlinks
392*b5893f02SDimitry Andric   // but can be very expensive on real file systems.
393*b5893f02SDimitry Andric   // FIXME: the semantic of RealPathName is unclear, and the name might be
394*b5893f02SDimitry Andric   // misleading. We need to clean up the interface here.
395*b5893f02SDimitry Andric   makeAbsolutePath(AbsPath);
396*b5893f02SDimitry Andric   llvm::sys::path::remove_dots(AbsPath, /*remove_dot_dot=*/true);
397*b5893f02SDimitry Andric   UFE->RealPathName = AbsPath.str();
398*b5893f02SDimitry Andric }
399*b5893f02SDimitry Andric 
40039d628a0SDimitry Andric llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
getBufferForFile(const FileEntry * Entry,bool isVolatile,bool ShouldCloseOpenFile)40139d628a0SDimitry Andric FileManager::getBufferForFile(const FileEntry *Entry, bool isVolatile,
40239d628a0SDimitry Andric                               bool ShouldCloseOpenFile) {
4037ae0e2c9SDimitry Andric   uint64_t FileSize = Entry->getSize();
4047ae0e2c9SDimitry Andric   // If there's a high enough chance that the file have changed since we
4057ae0e2c9SDimitry Andric   // got its size, force a stat before opening it.
4067ae0e2c9SDimitry Andric   if (isVolatile)
4077ae0e2c9SDimitry Andric     FileSize = -1;
4087ae0e2c9SDimitry Andric 
40944290647SDimitry Andric   StringRef Filename = Entry->getName();
4102754fe60SDimitry Andric   // If the file is already open, use the open file descriptor.
41159d1ed5bSDimitry Andric   if (Entry->File) {
41239d628a0SDimitry Andric     auto Result =
41339d628a0SDimitry Andric         Entry->File->getBuffer(Filename, FileSize,
41459d1ed5bSDimitry Andric                                /*RequiresNullTerminator=*/true, isVolatile);
41559d1ed5bSDimitry Andric     // FIXME: we need a set of APIs that can make guarantees about whether a
41659d1ed5bSDimitry Andric     // FileEntry is open or not.
41759d1ed5bSDimitry Andric     if (ShouldCloseOpenFile)
41859d1ed5bSDimitry Andric       Entry->closeFile();
41939d628a0SDimitry Andric     return Result;
4202754fe60SDimitry Andric   }
4212754fe60SDimitry Andric 
4222754fe60SDimitry Andric   // Otherwise, open the file.
4233b0f4066SDimitry Andric 
42439d628a0SDimitry Andric   if (FileSystemOpts.WorkingDir.empty())
42539d628a0SDimitry Andric     return FS->getBufferForFile(Filename, FileSize,
42659d1ed5bSDimitry Andric                                 /*RequiresNullTerminator=*/true, isVolatile);
4272754fe60SDimitry Andric 
428dff0c46cSDimitry Andric   SmallString<128> FilePath(Entry->getName());
4293b0f4066SDimitry Andric   FixupRelativePath(FilePath);
43033956c43SDimitry Andric   return FS->getBufferForFile(FilePath, FileSize,
43159d1ed5bSDimitry Andric                               /*RequiresNullTerminator=*/true, isVolatile);
4322754fe60SDimitry Andric }
4332754fe60SDimitry Andric 
43439d628a0SDimitry Andric llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
getBufferForFile(StringRef Filename,bool isVolatile)4354ba319b5SDimitry Andric FileManager::getBufferForFile(StringRef Filename, bool isVolatile) {
43639d628a0SDimitry Andric   if (FileSystemOpts.WorkingDir.empty())
4374ba319b5SDimitry Andric     return FS->getBufferForFile(Filename, -1, true, isVolatile);
4382754fe60SDimitry Andric 
439dff0c46cSDimitry Andric   SmallString<128> FilePath(Filename);
4403b0f4066SDimitry Andric   FixupRelativePath(FilePath);
4414ba319b5SDimitry Andric   return FS->getBufferForFile(FilePath.c_str(), -1, true, isVolatile);
4422754fe60SDimitry Andric }
4432754fe60SDimitry Andric 
4442754fe60SDimitry Andric /// getStatValue - Get the 'stat' information for the specified path,
4452754fe60SDimitry Andric /// using the cache to accelerate it if possible.  This returns true
4462754fe60SDimitry Andric /// if the path points to a virtual file or does not exist, or returns
4472754fe60SDimitry Andric /// false if it's an existent real file.  If FileDescriptor is NULL,
4482754fe60SDimitry Andric /// do directory look-up instead of file look-up.
getStatValue(StringRef Path,FileData & Data,bool isFile,std::unique_ptr<llvm::vfs::File> * F)44944290647SDimitry Andric bool FileManager::getStatValue(StringRef Path, FileData &Data, bool isFile,
450*b5893f02SDimitry Andric                                std::unique_ptr<llvm::vfs::File> *F) {
4512754fe60SDimitry Andric   // FIXME: FileSystemOpts shouldn't be passed in here, all paths should be
4522754fe60SDimitry Andric   // absolute!
4532754fe60SDimitry Andric   if (FileSystemOpts.WorkingDir.empty())
45459d1ed5bSDimitry Andric     return FileSystemStatCache::get(Path, Data, isFile, F,StatCache.get(), *FS);
4552754fe60SDimitry Andric 
456dff0c46cSDimitry Andric   SmallString<128> FilePath(Path);
4573b0f4066SDimitry Andric   FixupRelativePath(FilePath);
4582754fe60SDimitry Andric 
45959d1ed5bSDimitry Andric   return FileSystemStatCache::get(FilePath.c_str(), Data, isFile, F,
46059d1ed5bSDimitry Andric                                   StatCache.get(), *FS);
4612754fe60SDimitry Andric }
4622754fe60SDimitry Andric 
getNoncachedStatValue(StringRef Path,llvm::vfs::Status & Result)4636122f3e6SDimitry Andric bool FileManager::getNoncachedStatValue(StringRef Path,
464*b5893f02SDimitry Andric                                         llvm::vfs::Status &Result) {
465dff0c46cSDimitry Andric   SmallString<128> FilePath(Path);
4663b0f4066SDimitry Andric   FixupRelativePath(FilePath);
4673b0f4066SDimitry Andric 
468*b5893f02SDimitry Andric   llvm::ErrorOr<llvm::vfs::Status> S = FS->status(FilePath.c_str());
46959d1ed5bSDimitry Andric   if (!S)
47059d1ed5bSDimitry Andric     return true;
47159d1ed5bSDimitry Andric   Result = *S;
47259d1ed5bSDimitry Andric   return false;
4733b0f4066SDimitry Andric }
4743b0f4066SDimitry Andric 
invalidateCache(const FileEntry * Entry)4757ae0e2c9SDimitry Andric void FileManager::invalidateCache(const FileEntry *Entry) {
4767ae0e2c9SDimitry Andric   assert(Entry && "Cannot invalidate a NULL FileEntry");
4777ae0e2c9SDimitry Andric 
4787ae0e2c9SDimitry Andric   SeenFileEntries.erase(Entry->getName());
4797ae0e2c9SDimitry Andric 
4807ae0e2c9SDimitry Andric   // FileEntry invalidation should not block future optimizations in the file
4817ae0e2c9SDimitry Andric   // caches. Possible alternatives are cache truncation (invalidate last N) or
4827ae0e2c9SDimitry Andric   // invalidation of the whole cache.
48359d1ed5bSDimitry Andric   UniqueRealFiles.erase(Entry->getUniqueID());
4847ae0e2c9SDimitry Andric }
4857ae0e2c9SDimitry Andric 
GetUniqueIDMapping(SmallVectorImpl<const FileEntry * > & UIDToFiles) const4862754fe60SDimitry Andric void FileManager::GetUniqueIDMapping(
4876122f3e6SDimitry Andric                    SmallVectorImpl<const FileEntry *> &UIDToFiles) const {
4882754fe60SDimitry Andric   UIDToFiles.clear();
4892754fe60SDimitry Andric   UIDToFiles.resize(NextFileUID);
4902754fe60SDimitry Andric 
4912754fe60SDimitry Andric   // Map file entries
4922754fe60SDimitry Andric   for (llvm::StringMap<FileEntry*, llvm::BumpPtrAllocator>::const_iterator
4932754fe60SDimitry Andric          FE = SeenFileEntries.begin(), FEEnd = SeenFileEntries.end();
4942754fe60SDimitry Andric        FE != FEEnd; ++FE)
4952754fe60SDimitry Andric     if (FE->getValue() && FE->getValue() != NON_EXISTENT_FILE)
4962754fe60SDimitry Andric       UIDToFiles[FE->getValue()->getUID()] = FE->getValue();
4972754fe60SDimitry Andric 
4982754fe60SDimitry Andric   // Map virtual file entries
4990623d748SDimitry Andric   for (const auto &VFE : VirtualFileEntries)
5000623d748SDimitry Andric     if (VFE && VFE.get() != NON_EXISTENT_FILE)
5010623d748SDimitry Andric       UIDToFiles[VFE->getUID()] = VFE.get();
5022754fe60SDimitry Andric }
5032754fe60SDimitry Andric 
modifyFileEntry(FileEntry * File,off_t Size,time_t ModificationTime)5047ae0e2c9SDimitry Andric void FileManager::modifyFileEntry(FileEntry *File,
5057ae0e2c9SDimitry Andric                                   off_t Size, time_t ModificationTime) {
5067ae0e2c9SDimitry Andric   File->Size = Size;
5077ae0e2c9SDimitry Andric   File->ModTime = ModificationTime;
5087ae0e2c9SDimitry Andric }
5097ae0e2c9SDimitry Andric 
getCanonicalName(const DirectoryEntry * Dir)510139f7f9bSDimitry Andric StringRef FileManager::getCanonicalName(const DirectoryEntry *Dir) {
511139f7f9bSDimitry Andric   // FIXME: use llvm::sys::fs::canonical() when it gets implemented
512139f7f9bSDimitry Andric   llvm::DenseMap<const DirectoryEntry *, llvm::StringRef>::iterator Known
513139f7f9bSDimitry Andric     = CanonicalDirNames.find(Dir);
514139f7f9bSDimitry Andric   if (Known != CanonicalDirNames.end())
515139f7f9bSDimitry Andric     return Known->second;
516139f7f9bSDimitry Andric 
517139f7f9bSDimitry Andric   StringRef CanonicalName(Dir->getName());
51839d628a0SDimitry Andric 
5194ba319b5SDimitry Andric   SmallString<4096> CanonicalNameBuf;
5204ba319b5SDimitry Andric   if (!FS->getRealPath(Dir->getName(), CanonicalNameBuf))
5210623d748SDimitry Andric     CanonicalName = StringRef(CanonicalNameBuf).copy(CanonicalNameStorage);
522139f7f9bSDimitry Andric 
523139f7f9bSDimitry Andric   CanonicalDirNames.insert(std::make_pair(Dir, CanonicalName));
524139f7f9bSDimitry Andric   return CanonicalName;
525139f7f9bSDimitry Andric }
5262754fe60SDimitry Andric 
PrintStats() const527f22ef01cSRoman Divacky void FileManager::PrintStats() const {
528f22ef01cSRoman Divacky   llvm::errs() << "\n*** File Manager Stats:\n";
5292754fe60SDimitry Andric   llvm::errs() << UniqueRealFiles.size() << " real files found, "
5302754fe60SDimitry Andric                << UniqueRealDirs.size() << " real dirs found.\n";
5312754fe60SDimitry Andric   llvm::errs() << VirtualFileEntries.size() << " virtual files found, "
5322754fe60SDimitry Andric                << VirtualDirectoryEntries.size() << " virtual dirs found.\n";
533f22ef01cSRoman Divacky   llvm::errs() << NumDirLookups << " dir lookups, "
534f22ef01cSRoman Divacky                << NumDirCacheMisses << " dir cache misses.\n";
535f22ef01cSRoman Divacky   llvm::errs() << NumFileLookups << " file lookups, "
536f22ef01cSRoman Divacky                << NumFileCacheMisses << " file cache misses.\n";
537f22ef01cSRoman Divacky 
538f22ef01cSRoman Divacky   //llvm::errs() << PagesMapped << BytesOfPagesMapped << FSLookups;
539f22ef01cSRoman Divacky }
540