1f4a2713aSLionel Sambuc //===--- FileManager.cpp - File System Probing and Caching ----------------===//
2f4a2713aSLionel Sambuc //
3f4a2713aSLionel Sambuc //                     The LLVM Compiler Infrastructure
4f4a2713aSLionel Sambuc //
5f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7f4a2713aSLionel Sambuc //
8f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9f4a2713aSLionel Sambuc //
10f4a2713aSLionel Sambuc //  This file implements the FileManager interface.
11f4a2713aSLionel Sambuc //
12f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
13f4a2713aSLionel Sambuc //
14f4a2713aSLionel Sambuc // TODO: This should index all interesting directories with dirent calls.
15f4a2713aSLionel Sambuc //  getdirentries ?
16f4a2713aSLionel Sambuc //  opendir/readdir_r/closedir ?
17f4a2713aSLionel Sambuc //
18f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
19f4a2713aSLionel Sambuc 
20f4a2713aSLionel Sambuc #include "clang/Basic/FileManager.h"
21f4a2713aSLionel Sambuc #include "clang/Basic/FileSystemStatCache.h"
22f4a2713aSLionel Sambuc #include "llvm/ADT/SmallString.h"
23f4a2713aSLionel Sambuc #include "llvm/Config/llvm-config.h"
24f4a2713aSLionel Sambuc #include "llvm/Support/FileSystem.h"
25f4a2713aSLionel Sambuc #include "llvm/Support/MemoryBuffer.h"
26f4a2713aSLionel Sambuc #include "llvm/Support/Path.h"
27f4a2713aSLionel Sambuc #include "llvm/Support/raw_ostream.h"
28f4a2713aSLionel Sambuc #include <map>
29f4a2713aSLionel Sambuc #include <set>
30f4a2713aSLionel Sambuc #include <string>
31*0a6a1f1dSLionel Sambuc #include <system_error>
32f4a2713aSLionel Sambuc 
33f4a2713aSLionel Sambuc using namespace clang;
34f4a2713aSLionel Sambuc 
35f4a2713aSLionel Sambuc /// NON_EXISTENT_DIR - A special value distinct from null that is used to
36f4a2713aSLionel Sambuc /// represent a dir name that doesn't exist on the disk.
37f4a2713aSLionel Sambuc #define NON_EXISTENT_DIR reinterpret_cast<DirectoryEntry*>((intptr_t)-1)
38f4a2713aSLionel Sambuc 
39f4a2713aSLionel Sambuc /// NON_EXISTENT_FILE - A special value distinct from null that is used to
40f4a2713aSLionel Sambuc /// represent a filename that doesn't exist on the disk.
41f4a2713aSLionel Sambuc #define NON_EXISTENT_FILE reinterpret_cast<FileEntry*>((intptr_t)-1)
42f4a2713aSLionel Sambuc 
43f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
44f4a2713aSLionel Sambuc // Common logic.
45f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
46f4a2713aSLionel Sambuc 
FileManager(const FileSystemOptions & FSO,IntrusiveRefCntPtr<vfs::FileSystem> FS)47*0a6a1f1dSLionel Sambuc FileManager::FileManager(const FileSystemOptions &FSO,
48*0a6a1f1dSLionel Sambuc                          IntrusiveRefCntPtr<vfs::FileSystem> FS)
49*0a6a1f1dSLionel Sambuc   : FS(FS), FileSystemOpts(FSO),
50f4a2713aSLionel Sambuc     SeenDirEntries(64), SeenFileEntries(64), NextFileUID(0) {
51f4a2713aSLionel Sambuc   NumDirLookups = NumFileLookups = 0;
52f4a2713aSLionel Sambuc   NumDirCacheMisses = NumFileCacheMisses = 0;
53*0a6a1f1dSLionel Sambuc 
54*0a6a1f1dSLionel Sambuc   // If the caller doesn't provide a virtual file system, just grab the real
55*0a6a1f1dSLionel Sambuc   // file system.
56*0a6a1f1dSLionel Sambuc   if (!FS)
57*0a6a1f1dSLionel Sambuc     this->FS = vfs::getRealFileSystem();
58f4a2713aSLionel Sambuc }
59f4a2713aSLionel Sambuc 
~FileManager()60f4a2713aSLionel Sambuc FileManager::~FileManager() {
61f4a2713aSLionel Sambuc   for (unsigned i = 0, e = VirtualFileEntries.size(); i != e; ++i)
62f4a2713aSLionel Sambuc     delete VirtualFileEntries[i];
63f4a2713aSLionel Sambuc   for (unsigned i = 0, e = VirtualDirectoryEntries.size(); i != e; ++i)
64f4a2713aSLionel Sambuc     delete VirtualDirectoryEntries[i];
65f4a2713aSLionel Sambuc }
66f4a2713aSLionel Sambuc 
addStatCache(std::unique_ptr<FileSystemStatCache> statCache,bool AtBeginning)67*0a6a1f1dSLionel Sambuc void FileManager::addStatCache(std::unique_ptr<FileSystemStatCache> statCache,
68f4a2713aSLionel Sambuc                                bool AtBeginning) {
69f4a2713aSLionel Sambuc   assert(statCache && "No stat cache provided?");
70*0a6a1f1dSLionel Sambuc   if (AtBeginning || !StatCache.get()) {
71*0a6a1f1dSLionel Sambuc     statCache->setNextStatCache(std::move(StatCache));
72*0a6a1f1dSLionel Sambuc     StatCache = std::move(statCache);
73f4a2713aSLionel Sambuc     return;
74f4a2713aSLionel Sambuc   }
75f4a2713aSLionel Sambuc 
76f4a2713aSLionel Sambuc   FileSystemStatCache *LastCache = StatCache.get();
77f4a2713aSLionel Sambuc   while (LastCache->getNextStatCache())
78f4a2713aSLionel Sambuc     LastCache = LastCache->getNextStatCache();
79f4a2713aSLionel Sambuc 
80*0a6a1f1dSLionel Sambuc   LastCache->setNextStatCache(std::move(statCache));
81f4a2713aSLionel Sambuc }
82f4a2713aSLionel Sambuc 
removeStatCache(FileSystemStatCache * statCache)83f4a2713aSLionel Sambuc void FileManager::removeStatCache(FileSystemStatCache *statCache) {
84f4a2713aSLionel Sambuc   if (!statCache)
85f4a2713aSLionel Sambuc     return;
86f4a2713aSLionel Sambuc 
87f4a2713aSLionel Sambuc   if (StatCache.get() == statCache) {
88f4a2713aSLionel Sambuc     // This is the first stat cache.
89*0a6a1f1dSLionel Sambuc     StatCache = StatCache->takeNextStatCache();
90f4a2713aSLionel Sambuc     return;
91f4a2713aSLionel Sambuc   }
92f4a2713aSLionel Sambuc 
93f4a2713aSLionel Sambuc   // Find the stat cache in the list.
94f4a2713aSLionel Sambuc   FileSystemStatCache *PrevCache = StatCache.get();
95f4a2713aSLionel Sambuc   while (PrevCache && PrevCache->getNextStatCache() != statCache)
96f4a2713aSLionel Sambuc     PrevCache = PrevCache->getNextStatCache();
97f4a2713aSLionel Sambuc 
98f4a2713aSLionel Sambuc   assert(PrevCache && "Stat cache not found for removal");
99*0a6a1f1dSLionel Sambuc   PrevCache->setNextStatCache(statCache->takeNextStatCache());
100f4a2713aSLionel Sambuc }
101f4a2713aSLionel Sambuc 
clearStatCaches()102f4a2713aSLionel Sambuc void FileManager::clearStatCaches() {
103*0a6a1f1dSLionel Sambuc   StatCache.reset();
104f4a2713aSLionel Sambuc }
105f4a2713aSLionel Sambuc 
106f4a2713aSLionel Sambuc /// \brief Retrieve the directory that the given file name resides in.
107f4a2713aSLionel Sambuc /// Filename can point to either a real file or a virtual file.
getDirectoryFromFile(FileManager & FileMgr,StringRef Filename,bool CacheFailure)108f4a2713aSLionel Sambuc static const DirectoryEntry *getDirectoryFromFile(FileManager &FileMgr,
109f4a2713aSLionel Sambuc                                                   StringRef Filename,
110f4a2713aSLionel Sambuc                                                   bool CacheFailure) {
111f4a2713aSLionel Sambuc   if (Filename.empty())
112*0a6a1f1dSLionel Sambuc     return nullptr;
113f4a2713aSLionel Sambuc 
114f4a2713aSLionel Sambuc   if (llvm::sys::path::is_separator(Filename[Filename.size() - 1]))
115*0a6a1f1dSLionel Sambuc     return nullptr; // If Filename is a directory.
116f4a2713aSLionel Sambuc 
117f4a2713aSLionel Sambuc   StringRef DirName = llvm::sys::path::parent_path(Filename);
118f4a2713aSLionel Sambuc   // Use the current directory if file has no path component.
119f4a2713aSLionel Sambuc   if (DirName.empty())
120f4a2713aSLionel Sambuc     DirName = ".";
121f4a2713aSLionel Sambuc 
122f4a2713aSLionel Sambuc   return FileMgr.getDirectory(DirName, CacheFailure);
123f4a2713aSLionel Sambuc }
124f4a2713aSLionel Sambuc 
125f4a2713aSLionel Sambuc /// Add all ancestors of the given path (pointing to either a file or
126f4a2713aSLionel Sambuc /// a directory) as virtual directories.
addAncestorsAsVirtualDirs(StringRef Path)127f4a2713aSLionel Sambuc void FileManager::addAncestorsAsVirtualDirs(StringRef Path) {
128f4a2713aSLionel Sambuc   StringRef DirName = llvm::sys::path::parent_path(Path);
129f4a2713aSLionel Sambuc   if (DirName.empty())
130f4a2713aSLionel Sambuc     return;
131f4a2713aSLionel Sambuc 
132*0a6a1f1dSLionel Sambuc   auto &NamedDirEnt =
133*0a6a1f1dSLionel Sambuc       *SeenDirEntries.insert(std::make_pair(DirName, nullptr)).first;
134f4a2713aSLionel Sambuc 
135f4a2713aSLionel Sambuc   // When caching a virtual directory, we always cache its ancestors
136f4a2713aSLionel Sambuc   // at the same time.  Therefore, if DirName is already in the cache,
137f4a2713aSLionel Sambuc   // we don't need to recurse as its ancestors must also already be in
138f4a2713aSLionel Sambuc   // the cache.
139*0a6a1f1dSLionel Sambuc   if (NamedDirEnt.second)
140f4a2713aSLionel Sambuc     return;
141f4a2713aSLionel Sambuc 
142f4a2713aSLionel Sambuc   // Add the virtual directory to the cache.
143f4a2713aSLionel Sambuc   DirectoryEntry *UDE = new DirectoryEntry;
144*0a6a1f1dSLionel Sambuc   UDE->Name = NamedDirEnt.first().data();
145*0a6a1f1dSLionel Sambuc   NamedDirEnt.second = UDE;
146f4a2713aSLionel Sambuc   VirtualDirectoryEntries.push_back(UDE);
147f4a2713aSLionel Sambuc 
148f4a2713aSLionel Sambuc   // Recursively add the other ancestors.
149f4a2713aSLionel Sambuc   addAncestorsAsVirtualDirs(DirName);
150f4a2713aSLionel Sambuc }
151f4a2713aSLionel Sambuc 
getDirectory(StringRef DirName,bool CacheFailure)152f4a2713aSLionel Sambuc const DirectoryEntry *FileManager::getDirectory(StringRef DirName,
153f4a2713aSLionel Sambuc                                                 bool CacheFailure) {
154f4a2713aSLionel Sambuc   // stat doesn't like trailing separators except for root directory.
155f4a2713aSLionel Sambuc   // At least, on Win32 MSVCRT, stat() cannot strip trailing '/'.
156f4a2713aSLionel Sambuc   // (though it can strip '\\')
157f4a2713aSLionel Sambuc   if (DirName.size() > 1 &&
158f4a2713aSLionel Sambuc       DirName != llvm::sys::path::root_path(DirName) &&
159f4a2713aSLionel Sambuc       llvm::sys::path::is_separator(DirName.back()))
160f4a2713aSLionel Sambuc     DirName = DirName.substr(0, DirName.size()-1);
161f4a2713aSLionel Sambuc #ifdef LLVM_ON_WIN32
162f4a2713aSLionel Sambuc   // Fixing a problem with "clang C:test.c" on Windows.
163f4a2713aSLionel Sambuc   // Stat("C:") does not recognize "C:" as a valid directory
164f4a2713aSLionel Sambuc   std::string DirNameStr;
165f4a2713aSLionel Sambuc   if (DirName.size() > 1 && DirName.back() == ':' &&
166f4a2713aSLionel Sambuc       DirName.equals_lower(llvm::sys::path::root_name(DirName))) {
167f4a2713aSLionel Sambuc     DirNameStr = DirName.str() + '.';
168f4a2713aSLionel Sambuc     DirName = DirNameStr;
169f4a2713aSLionel Sambuc   }
170f4a2713aSLionel Sambuc #endif
171f4a2713aSLionel Sambuc 
172f4a2713aSLionel Sambuc   ++NumDirLookups;
173*0a6a1f1dSLionel Sambuc   auto &NamedDirEnt =
174*0a6a1f1dSLionel Sambuc       *SeenDirEntries.insert(std::make_pair(DirName, nullptr)).first;
175f4a2713aSLionel Sambuc 
176f4a2713aSLionel Sambuc   // See if there was already an entry in the map.  Note that the map
177f4a2713aSLionel Sambuc   // contains both virtual and real directories.
178*0a6a1f1dSLionel Sambuc   if (NamedDirEnt.second)
179*0a6a1f1dSLionel Sambuc     return NamedDirEnt.second == NON_EXISTENT_DIR ? nullptr
180*0a6a1f1dSLionel Sambuc                                                   : NamedDirEnt.second;
181f4a2713aSLionel Sambuc 
182f4a2713aSLionel Sambuc   ++NumDirCacheMisses;
183f4a2713aSLionel Sambuc 
184f4a2713aSLionel Sambuc   // By default, initialize it to invalid.
185*0a6a1f1dSLionel Sambuc   NamedDirEnt.second = NON_EXISTENT_DIR;
186f4a2713aSLionel Sambuc 
187f4a2713aSLionel Sambuc   // Get the null-terminated directory name as stored as the key of the
188f4a2713aSLionel Sambuc   // SeenDirEntries map.
189*0a6a1f1dSLionel Sambuc   const char *InterndDirName = NamedDirEnt.first().data();
190f4a2713aSLionel Sambuc 
191f4a2713aSLionel Sambuc   // Check to see if the directory exists.
192f4a2713aSLionel Sambuc   FileData Data;
193*0a6a1f1dSLionel Sambuc   if (getStatValue(InterndDirName, Data, false, nullptr /*directory lookup*/)) {
194f4a2713aSLionel Sambuc     // There's no real directory at the given path.
195f4a2713aSLionel Sambuc     if (!CacheFailure)
196f4a2713aSLionel Sambuc       SeenDirEntries.erase(DirName);
197*0a6a1f1dSLionel Sambuc     return nullptr;
198f4a2713aSLionel Sambuc   }
199f4a2713aSLionel Sambuc 
200f4a2713aSLionel Sambuc   // It exists.  See if we have already opened a directory with the
201f4a2713aSLionel Sambuc   // same inode (this occurs on Unix-like systems when one dir is
202f4a2713aSLionel Sambuc   // symlinked to another, for example) or the same path (on
203f4a2713aSLionel Sambuc   // Windows).
204*0a6a1f1dSLionel Sambuc   DirectoryEntry &UDE = UniqueRealDirs[Data.UniqueID];
205f4a2713aSLionel Sambuc 
206*0a6a1f1dSLionel Sambuc   NamedDirEnt.second = &UDE;
207f4a2713aSLionel Sambuc   if (!UDE.getName()) {
208f4a2713aSLionel Sambuc     // We don't have this directory yet, add it.  We use the string
209f4a2713aSLionel Sambuc     // key from the SeenDirEntries map as the string.
210f4a2713aSLionel Sambuc     UDE.Name  = InterndDirName;
211f4a2713aSLionel Sambuc   }
212f4a2713aSLionel Sambuc 
213f4a2713aSLionel Sambuc   return &UDE;
214f4a2713aSLionel Sambuc }
215f4a2713aSLionel Sambuc 
getFile(StringRef Filename,bool openFile,bool CacheFailure)216f4a2713aSLionel Sambuc const FileEntry *FileManager::getFile(StringRef Filename, bool openFile,
217f4a2713aSLionel Sambuc                                       bool CacheFailure) {
218f4a2713aSLionel Sambuc   ++NumFileLookups;
219f4a2713aSLionel Sambuc 
220f4a2713aSLionel Sambuc   // See if there is already an entry in the map.
221*0a6a1f1dSLionel Sambuc   auto &NamedFileEnt =
222*0a6a1f1dSLionel Sambuc       *SeenFileEntries.insert(std::make_pair(Filename, nullptr)).first;
223f4a2713aSLionel Sambuc 
224f4a2713aSLionel Sambuc   // See if there is already an entry in the map.
225*0a6a1f1dSLionel Sambuc   if (NamedFileEnt.second)
226*0a6a1f1dSLionel Sambuc     return NamedFileEnt.second == NON_EXISTENT_FILE ? nullptr
227*0a6a1f1dSLionel Sambuc                                                     : NamedFileEnt.second;
228f4a2713aSLionel Sambuc 
229f4a2713aSLionel Sambuc   ++NumFileCacheMisses;
230f4a2713aSLionel Sambuc 
231f4a2713aSLionel Sambuc   // By default, initialize it to invalid.
232*0a6a1f1dSLionel Sambuc   NamedFileEnt.second = NON_EXISTENT_FILE;
233f4a2713aSLionel Sambuc 
234f4a2713aSLionel Sambuc   // Get the null-terminated file name as stored as the key of the
235f4a2713aSLionel Sambuc   // SeenFileEntries map.
236*0a6a1f1dSLionel Sambuc   const char *InterndFileName = NamedFileEnt.first().data();
237f4a2713aSLionel Sambuc 
238f4a2713aSLionel Sambuc   // Look up the directory for the file.  When looking up something like
239f4a2713aSLionel Sambuc   // sys/foo.h we'll discover all of the search directories that have a 'sys'
240f4a2713aSLionel Sambuc   // subdirectory.  This will let us avoid having to waste time on known-to-fail
241f4a2713aSLionel Sambuc   // searches when we go to find sys/bar.h, because all the search directories
242f4a2713aSLionel Sambuc   // without a 'sys' subdir will get a cached failure result.
243f4a2713aSLionel Sambuc   const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename,
244f4a2713aSLionel Sambuc                                                        CacheFailure);
245*0a6a1f1dSLionel Sambuc   if (DirInfo == nullptr) { // Directory doesn't exist, file can't exist.
246f4a2713aSLionel Sambuc     if (!CacheFailure)
247f4a2713aSLionel Sambuc       SeenFileEntries.erase(Filename);
248f4a2713aSLionel Sambuc 
249*0a6a1f1dSLionel Sambuc     return nullptr;
250f4a2713aSLionel Sambuc   }
251f4a2713aSLionel Sambuc 
252f4a2713aSLionel Sambuc   // FIXME: Use the directory info to prune this, before doing the stat syscall.
253f4a2713aSLionel Sambuc   // FIXME: This will reduce the # syscalls.
254f4a2713aSLionel Sambuc 
255f4a2713aSLionel Sambuc   // Nope, there isn't.  Check to see if the file exists.
256*0a6a1f1dSLionel Sambuc   std::unique_ptr<vfs::File> F;
257f4a2713aSLionel Sambuc   FileData Data;
258*0a6a1f1dSLionel Sambuc   if (getStatValue(InterndFileName, Data, true, openFile ? &F : nullptr)) {
259f4a2713aSLionel Sambuc     // There's no real file at the given path.
260f4a2713aSLionel Sambuc     if (!CacheFailure)
261f4a2713aSLionel Sambuc       SeenFileEntries.erase(Filename);
262f4a2713aSLionel Sambuc 
263*0a6a1f1dSLionel Sambuc     return nullptr;
264f4a2713aSLionel Sambuc   }
265f4a2713aSLionel Sambuc 
266*0a6a1f1dSLionel Sambuc   assert((openFile || !F) && "undesired open file");
267f4a2713aSLionel Sambuc 
268f4a2713aSLionel Sambuc   // It exists.  See if we have already opened a file with the same inode.
269f4a2713aSLionel Sambuc   // This occurs when one dir is symlinked to another, for example.
270*0a6a1f1dSLionel Sambuc   FileEntry &UFE = UniqueRealFiles[Data.UniqueID];
271f4a2713aSLionel Sambuc 
272*0a6a1f1dSLionel Sambuc   NamedFileEnt.second = &UFE;
273*0a6a1f1dSLionel Sambuc 
274*0a6a1f1dSLionel Sambuc   // If the name returned by getStatValue is different than Filename, re-intern
275*0a6a1f1dSLionel Sambuc   // the name.
276*0a6a1f1dSLionel Sambuc   if (Data.Name != Filename) {
277*0a6a1f1dSLionel Sambuc     auto &NamedFileEnt =
278*0a6a1f1dSLionel Sambuc         *SeenFileEntries.insert(std::make_pair(Data.Name, nullptr)).first;
279*0a6a1f1dSLionel Sambuc     if (!NamedFileEnt.second)
280*0a6a1f1dSLionel Sambuc       NamedFileEnt.second = &UFE;
281*0a6a1f1dSLionel Sambuc     else
282*0a6a1f1dSLionel Sambuc       assert(NamedFileEnt.second == &UFE &&
283*0a6a1f1dSLionel Sambuc              "filename from getStatValue() refers to wrong file");
284*0a6a1f1dSLionel Sambuc     InterndFileName = NamedFileEnt.first().data();
285*0a6a1f1dSLionel Sambuc   }
286*0a6a1f1dSLionel Sambuc 
287*0a6a1f1dSLionel Sambuc   if (UFE.isValid()) { // Already have an entry with this inode, return it.
288*0a6a1f1dSLionel Sambuc 
289*0a6a1f1dSLionel Sambuc     // FIXME: this hack ensures that if we look up a file by a virtual path in
290*0a6a1f1dSLionel Sambuc     // the VFS that the getDir() will have the virtual path, even if we found
291*0a6a1f1dSLionel Sambuc     // the file by a 'real' path first. This is required in order to find a
292*0a6a1f1dSLionel Sambuc     // module's structure when its headers/module map are mapped in the VFS.
293*0a6a1f1dSLionel Sambuc     // We should remove this as soon as we can properly support a file having
294*0a6a1f1dSLionel Sambuc     // multiple names.
295*0a6a1f1dSLionel Sambuc     if (DirInfo != UFE.Dir && Data.IsVFSMapped)
296*0a6a1f1dSLionel Sambuc       UFE.Dir = DirInfo;
297*0a6a1f1dSLionel Sambuc 
298*0a6a1f1dSLionel Sambuc     // Always update the name to use the last name by which a file was accessed.
299*0a6a1f1dSLionel Sambuc     // FIXME: Neither this nor always using the first name is correct; we want
300*0a6a1f1dSLionel Sambuc     // to switch towards a design where we return a FileName object that
301*0a6a1f1dSLionel Sambuc     // encapsulates both the name by which the file was accessed and the
302*0a6a1f1dSLionel Sambuc     // corresponding FileEntry.
303*0a6a1f1dSLionel Sambuc     UFE.Name = InterndFileName;
304f4a2713aSLionel Sambuc 
305f4a2713aSLionel Sambuc     return &UFE;
306f4a2713aSLionel Sambuc   }
307f4a2713aSLionel Sambuc 
308*0a6a1f1dSLionel Sambuc   // Otherwise, we don't have this file yet, add it.
309f4a2713aSLionel Sambuc   UFE.Name    = InterndFileName;
310f4a2713aSLionel Sambuc   UFE.Size = Data.Size;
311f4a2713aSLionel Sambuc   UFE.ModTime = Data.ModTime;
312f4a2713aSLionel Sambuc   UFE.Dir     = DirInfo;
313f4a2713aSLionel Sambuc   UFE.UID     = NextFileUID++;
314*0a6a1f1dSLionel Sambuc   UFE.UniqueID = Data.UniqueID;
315*0a6a1f1dSLionel Sambuc   UFE.IsNamedPipe = Data.IsNamedPipe;
316*0a6a1f1dSLionel Sambuc   UFE.InPCH = Data.InPCH;
317*0a6a1f1dSLionel Sambuc   UFE.File = std::move(F);
318*0a6a1f1dSLionel Sambuc   UFE.IsValid = true;
319f4a2713aSLionel Sambuc   return &UFE;
320f4a2713aSLionel Sambuc }
321f4a2713aSLionel Sambuc 
322f4a2713aSLionel Sambuc const FileEntry *
getVirtualFile(StringRef Filename,off_t Size,time_t ModificationTime)323f4a2713aSLionel Sambuc FileManager::getVirtualFile(StringRef Filename, off_t Size,
324f4a2713aSLionel Sambuc                             time_t ModificationTime) {
325f4a2713aSLionel Sambuc   ++NumFileLookups;
326f4a2713aSLionel Sambuc 
327f4a2713aSLionel Sambuc   // See if there is already an entry in the map.
328*0a6a1f1dSLionel Sambuc   auto &NamedFileEnt =
329*0a6a1f1dSLionel Sambuc       *SeenFileEntries.insert(std::make_pair(Filename, nullptr)).first;
330f4a2713aSLionel Sambuc 
331f4a2713aSLionel Sambuc   // See if there is already an entry in the map.
332*0a6a1f1dSLionel Sambuc   if (NamedFileEnt.second && NamedFileEnt.second != NON_EXISTENT_FILE)
333*0a6a1f1dSLionel Sambuc     return NamedFileEnt.second;
334f4a2713aSLionel Sambuc 
335f4a2713aSLionel Sambuc   ++NumFileCacheMisses;
336f4a2713aSLionel Sambuc 
337f4a2713aSLionel Sambuc   // By default, initialize it to invalid.
338*0a6a1f1dSLionel Sambuc   NamedFileEnt.second = NON_EXISTENT_FILE;
339f4a2713aSLionel Sambuc 
340f4a2713aSLionel Sambuc   addAncestorsAsVirtualDirs(Filename);
341*0a6a1f1dSLionel Sambuc   FileEntry *UFE = nullptr;
342f4a2713aSLionel Sambuc 
343f4a2713aSLionel Sambuc   // Now that all ancestors of Filename are in the cache, the
344f4a2713aSLionel Sambuc   // following call is guaranteed to find the DirectoryEntry from the
345f4a2713aSLionel Sambuc   // cache.
346f4a2713aSLionel Sambuc   const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename,
347f4a2713aSLionel Sambuc                                                        /*CacheFailure=*/true);
348f4a2713aSLionel Sambuc   assert(DirInfo &&
349f4a2713aSLionel Sambuc          "The directory of a virtual file should already be in the cache.");
350f4a2713aSLionel Sambuc 
351f4a2713aSLionel Sambuc   // Check to see if the file exists. If so, drop the virtual file
352f4a2713aSLionel Sambuc   FileData Data;
353*0a6a1f1dSLionel Sambuc   const char *InterndFileName = NamedFileEnt.first().data();
354*0a6a1f1dSLionel Sambuc   if (getStatValue(InterndFileName, Data, true, nullptr) == 0) {
355f4a2713aSLionel Sambuc     Data.Size = Size;
356f4a2713aSLionel Sambuc     Data.ModTime = ModificationTime;
357*0a6a1f1dSLionel Sambuc     UFE = &UniqueRealFiles[Data.UniqueID];
358f4a2713aSLionel Sambuc 
359*0a6a1f1dSLionel Sambuc     NamedFileEnt.second = UFE;
360f4a2713aSLionel Sambuc 
361f4a2713aSLionel Sambuc     // If we had already opened this file, close it now so we don't
362f4a2713aSLionel Sambuc     // leak the descriptor. We're not going to use the file
363f4a2713aSLionel Sambuc     // descriptor anyway, since this is a virtual file.
364*0a6a1f1dSLionel Sambuc     if (UFE->File)
365*0a6a1f1dSLionel Sambuc       UFE->closeFile();
366f4a2713aSLionel Sambuc 
367f4a2713aSLionel Sambuc     // If we already have an entry with this inode, return it.
368*0a6a1f1dSLionel Sambuc     if (UFE->isValid())
369f4a2713aSLionel Sambuc       return UFE;
370*0a6a1f1dSLionel Sambuc 
371*0a6a1f1dSLionel Sambuc     UFE->UniqueID = Data.UniqueID;
372*0a6a1f1dSLionel Sambuc     UFE->IsNamedPipe = Data.IsNamedPipe;
373*0a6a1f1dSLionel Sambuc     UFE->InPCH = Data.InPCH;
374f4a2713aSLionel Sambuc   }
375f4a2713aSLionel Sambuc 
376f4a2713aSLionel Sambuc   if (!UFE) {
377f4a2713aSLionel Sambuc     UFE = new FileEntry();
378f4a2713aSLionel Sambuc     VirtualFileEntries.push_back(UFE);
379*0a6a1f1dSLionel Sambuc     NamedFileEnt.second = UFE;
380f4a2713aSLionel Sambuc   }
381f4a2713aSLionel Sambuc 
382f4a2713aSLionel Sambuc   UFE->Name    = InterndFileName;
383f4a2713aSLionel Sambuc   UFE->Size    = Size;
384f4a2713aSLionel Sambuc   UFE->ModTime = ModificationTime;
385f4a2713aSLionel Sambuc   UFE->Dir     = DirInfo;
386f4a2713aSLionel Sambuc   UFE->UID     = NextFileUID++;
387*0a6a1f1dSLionel Sambuc   UFE->File.reset();
388f4a2713aSLionel Sambuc   return UFE;
389f4a2713aSLionel Sambuc }
390f4a2713aSLionel Sambuc 
FixupRelativePath(SmallVectorImpl<char> & path) const391f4a2713aSLionel Sambuc void FileManager::FixupRelativePath(SmallVectorImpl<char> &path) const {
392f4a2713aSLionel Sambuc   StringRef pathRef(path.data(), path.size());
393f4a2713aSLionel Sambuc 
394f4a2713aSLionel Sambuc   if (FileSystemOpts.WorkingDir.empty()
395f4a2713aSLionel Sambuc       || llvm::sys::path::is_absolute(pathRef))
396f4a2713aSLionel Sambuc     return;
397f4a2713aSLionel Sambuc 
398f4a2713aSLionel Sambuc   SmallString<128> NewPath(FileSystemOpts.WorkingDir);
399f4a2713aSLionel Sambuc   llvm::sys::path::append(NewPath, pathRef);
400f4a2713aSLionel Sambuc   path = NewPath;
401f4a2713aSLionel Sambuc }
402f4a2713aSLionel Sambuc 
403*0a6a1f1dSLionel Sambuc llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
getBufferForFile(const FileEntry * Entry,bool isVolatile,bool ShouldCloseOpenFile)404*0a6a1f1dSLionel Sambuc FileManager::getBufferForFile(const FileEntry *Entry, bool isVolatile,
405*0a6a1f1dSLionel Sambuc                               bool ShouldCloseOpenFile) {
406f4a2713aSLionel Sambuc   uint64_t FileSize = Entry->getSize();
407f4a2713aSLionel Sambuc   // If there's a high enough chance that the file have changed since we
408f4a2713aSLionel Sambuc   // got its size, force a stat before opening it.
409f4a2713aSLionel Sambuc   if (isVolatile)
410f4a2713aSLionel Sambuc     FileSize = -1;
411f4a2713aSLionel Sambuc 
412f4a2713aSLionel Sambuc   const char *Filename = Entry->getName();
413f4a2713aSLionel Sambuc   // If the file is already open, use the open file descriptor.
414*0a6a1f1dSLionel Sambuc   if (Entry->File) {
415*0a6a1f1dSLionel Sambuc     auto Result =
416*0a6a1f1dSLionel Sambuc         Entry->File->getBuffer(Filename, FileSize,
417*0a6a1f1dSLionel Sambuc                                /*RequiresNullTerminator=*/true, isVolatile);
418*0a6a1f1dSLionel Sambuc     // FIXME: we need a set of APIs that can make guarantees about whether a
419*0a6a1f1dSLionel Sambuc     // FileEntry is open or not.
420*0a6a1f1dSLionel Sambuc     if (ShouldCloseOpenFile)
421*0a6a1f1dSLionel Sambuc       Entry->closeFile();
422*0a6a1f1dSLionel Sambuc     return Result;
423f4a2713aSLionel Sambuc   }
424f4a2713aSLionel Sambuc 
425f4a2713aSLionel Sambuc   // Otherwise, open the file.
426f4a2713aSLionel Sambuc 
427*0a6a1f1dSLionel Sambuc   if (FileSystemOpts.WorkingDir.empty())
428*0a6a1f1dSLionel Sambuc     return FS->getBufferForFile(Filename, FileSize,
429*0a6a1f1dSLionel Sambuc                                 /*RequiresNullTerminator=*/true, isVolatile);
430f4a2713aSLionel Sambuc 
431f4a2713aSLionel Sambuc   SmallString<128> FilePath(Entry->getName());
432f4a2713aSLionel Sambuc   FixupRelativePath(FilePath);
433*0a6a1f1dSLionel Sambuc   return FS->getBufferForFile(FilePath.str(), FileSize,
434*0a6a1f1dSLionel Sambuc                               /*RequiresNullTerminator=*/true, isVolatile);
435f4a2713aSLionel Sambuc }
436f4a2713aSLionel Sambuc 
437*0a6a1f1dSLionel Sambuc llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
getBufferForFile(StringRef Filename)438*0a6a1f1dSLionel Sambuc FileManager::getBufferForFile(StringRef Filename) {
439*0a6a1f1dSLionel Sambuc   if (FileSystemOpts.WorkingDir.empty())
440*0a6a1f1dSLionel Sambuc     return FS->getBufferForFile(Filename);
441f4a2713aSLionel Sambuc 
442f4a2713aSLionel Sambuc   SmallString<128> FilePath(Filename);
443f4a2713aSLionel Sambuc   FixupRelativePath(FilePath);
444*0a6a1f1dSLionel Sambuc   return FS->getBufferForFile(FilePath.c_str());
445f4a2713aSLionel Sambuc }
446f4a2713aSLionel Sambuc 
447f4a2713aSLionel Sambuc /// getStatValue - Get the 'stat' information for the specified path,
448f4a2713aSLionel Sambuc /// using the cache to accelerate it if possible.  This returns true
449f4a2713aSLionel Sambuc /// if the path points to a virtual file or does not exist, or returns
450f4a2713aSLionel Sambuc /// false if it's an existent real file.  If FileDescriptor is NULL,
451f4a2713aSLionel Sambuc /// do directory look-up instead of file look-up.
getStatValue(const char * Path,FileData & Data,bool isFile,std::unique_ptr<vfs::File> * F)452f4a2713aSLionel Sambuc bool FileManager::getStatValue(const char *Path, FileData &Data, bool isFile,
453*0a6a1f1dSLionel Sambuc                                std::unique_ptr<vfs::File> *F) {
454f4a2713aSLionel Sambuc   // FIXME: FileSystemOpts shouldn't be passed in here, all paths should be
455f4a2713aSLionel Sambuc   // absolute!
456f4a2713aSLionel Sambuc   if (FileSystemOpts.WorkingDir.empty())
457*0a6a1f1dSLionel Sambuc     return FileSystemStatCache::get(Path, Data, isFile, F,StatCache.get(), *FS);
458f4a2713aSLionel Sambuc 
459f4a2713aSLionel Sambuc   SmallString<128> FilePath(Path);
460f4a2713aSLionel Sambuc   FixupRelativePath(FilePath);
461f4a2713aSLionel Sambuc 
462*0a6a1f1dSLionel Sambuc   return FileSystemStatCache::get(FilePath.c_str(), Data, isFile, F,
463*0a6a1f1dSLionel Sambuc                                   StatCache.get(), *FS);
464f4a2713aSLionel Sambuc }
465f4a2713aSLionel Sambuc 
getNoncachedStatValue(StringRef Path,vfs::Status & Result)466f4a2713aSLionel Sambuc bool FileManager::getNoncachedStatValue(StringRef Path,
467*0a6a1f1dSLionel Sambuc                                         vfs::Status &Result) {
468f4a2713aSLionel Sambuc   SmallString<128> FilePath(Path);
469f4a2713aSLionel Sambuc   FixupRelativePath(FilePath);
470f4a2713aSLionel Sambuc 
471*0a6a1f1dSLionel Sambuc   llvm::ErrorOr<vfs::Status> S = FS->status(FilePath.c_str());
472*0a6a1f1dSLionel Sambuc   if (!S)
473*0a6a1f1dSLionel Sambuc     return true;
474*0a6a1f1dSLionel Sambuc   Result = *S;
475*0a6a1f1dSLionel Sambuc   return false;
476f4a2713aSLionel Sambuc }
477f4a2713aSLionel Sambuc 
invalidateCache(const FileEntry * Entry)478f4a2713aSLionel Sambuc void FileManager::invalidateCache(const FileEntry *Entry) {
479f4a2713aSLionel Sambuc   assert(Entry && "Cannot invalidate a NULL FileEntry");
480f4a2713aSLionel Sambuc 
481f4a2713aSLionel Sambuc   SeenFileEntries.erase(Entry->getName());
482f4a2713aSLionel Sambuc 
483f4a2713aSLionel Sambuc   // FileEntry invalidation should not block future optimizations in the file
484f4a2713aSLionel Sambuc   // caches. Possible alternatives are cache truncation (invalidate last N) or
485f4a2713aSLionel Sambuc   // invalidation of the whole cache.
486*0a6a1f1dSLionel Sambuc   UniqueRealFiles.erase(Entry->getUniqueID());
487f4a2713aSLionel Sambuc }
488f4a2713aSLionel Sambuc 
489f4a2713aSLionel Sambuc 
GetUniqueIDMapping(SmallVectorImpl<const FileEntry * > & UIDToFiles) const490f4a2713aSLionel Sambuc void FileManager::GetUniqueIDMapping(
491f4a2713aSLionel Sambuc                    SmallVectorImpl<const FileEntry *> &UIDToFiles) const {
492f4a2713aSLionel Sambuc   UIDToFiles.clear();
493f4a2713aSLionel Sambuc   UIDToFiles.resize(NextFileUID);
494f4a2713aSLionel Sambuc 
495f4a2713aSLionel Sambuc   // Map file entries
496f4a2713aSLionel Sambuc   for (llvm::StringMap<FileEntry*, llvm::BumpPtrAllocator>::const_iterator
497f4a2713aSLionel Sambuc          FE = SeenFileEntries.begin(), FEEnd = SeenFileEntries.end();
498f4a2713aSLionel Sambuc        FE != FEEnd; ++FE)
499f4a2713aSLionel Sambuc     if (FE->getValue() && FE->getValue() != NON_EXISTENT_FILE)
500f4a2713aSLionel Sambuc       UIDToFiles[FE->getValue()->getUID()] = FE->getValue();
501f4a2713aSLionel Sambuc 
502f4a2713aSLionel Sambuc   // Map virtual file entries
503f4a2713aSLionel Sambuc   for (SmallVectorImpl<FileEntry *>::const_iterator
504f4a2713aSLionel Sambuc          VFE = VirtualFileEntries.begin(), VFEEnd = VirtualFileEntries.end();
505f4a2713aSLionel Sambuc        VFE != VFEEnd; ++VFE)
506f4a2713aSLionel Sambuc     if (*VFE && *VFE != NON_EXISTENT_FILE)
507f4a2713aSLionel Sambuc       UIDToFiles[(*VFE)->getUID()] = *VFE;
508f4a2713aSLionel Sambuc }
509f4a2713aSLionel Sambuc 
modifyFileEntry(FileEntry * File,off_t Size,time_t ModificationTime)510f4a2713aSLionel Sambuc void FileManager::modifyFileEntry(FileEntry *File,
511f4a2713aSLionel Sambuc                                   off_t Size, time_t ModificationTime) {
512f4a2713aSLionel Sambuc   File->Size = Size;
513f4a2713aSLionel Sambuc   File->ModTime = ModificationTime;
514f4a2713aSLionel Sambuc }
515f4a2713aSLionel Sambuc 
516*0a6a1f1dSLionel Sambuc /// Remove '.' path components from the given absolute path.
517*0a6a1f1dSLionel Sambuc /// \return \c true if any changes were made.
518*0a6a1f1dSLionel Sambuc // FIXME: Move this to llvm::sys::path.
removeDotPaths(SmallVectorImpl<char> & Path)519*0a6a1f1dSLionel Sambuc bool FileManager::removeDotPaths(SmallVectorImpl<char> &Path) {
520*0a6a1f1dSLionel Sambuc   using namespace llvm::sys;
521*0a6a1f1dSLionel Sambuc 
522*0a6a1f1dSLionel Sambuc   SmallVector<StringRef, 16> ComponentStack;
523*0a6a1f1dSLionel Sambuc   StringRef P(Path.data(), Path.size());
524*0a6a1f1dSLionel Sambuc 
525*0a6a1f1dSLionel Sambuc   // Skip the root path, then look for traversal in the components.
526*0a6a1f1dSLionel Sambuc   StringRef Rel = path::relative_path(P);
527*0a6a1f1dSLionel Sambuc   bool AnyDots = false;
528*0a6a1f1dSLionel Sambuc   for (StringRef C : llvm::make_range(path::begin(Rel), path::end(Rel))) {
529*0a6a1f1dSLionel Sambuc     if (C == ".") {
530*0a6a1f1dSLionel Sambuc       AnyDots = true;
531*0a6a1f1dSLionel Sambuc       continue;
532*0a6a1f1dSLionel Sambuc     }
533*0a6a1f1dSLionel Sambuc     ComponentStack.push_back(C);
534*0a6a1f1dSLionel Sambuc   }
535*0a6a1f1dSLionel Sambuc 
536*0a6a1f1dSLionel Sambuc   if (!AnyDots)
537*0a6a1f1dSLionel Sambuc     return false;
538*0a6a1f1dSLionel Sambuc 
539*0a6a1f1dSLionel Sambuc   SmallString<256> Buffer = path::root_path(P);
540*0a6a1f1dSLionel Sambuc   for (StringRef C : ComponentStack)
541*0a6a1f1dSLionel Sambuc     path::append(Buffer, C);
542*0a6a1f1dSLionel Sambuc 
543*0a6a1f1dSLionel Sambuc   Path.swap(Buffer);
544*0a6a1f1dSLionel Sambuc   return true;
545*0a6a1f1dSLionel Sambuc }
546*0a6a1f1dSLionel Sambuc 
getCanonicalName(const DirectoryEntry * Dir)547f4a2713aSLionel Sambuc StringRef FileManager::getCanonicalName(const DirectoryEntry *Dir) {
548f4a2713aSLionel Sambuc   // FIXME: use llvm::sys::fs::canonical() when it gets implemented
549f4a2713aSLionel Sambuc   llvm::DenseMap<const DirectoryEntry *, llvm::StringRef>::iterator Known
550f4a2713aSLionel Sambuc     = CanonicalDirNames.find(Dir);
551f4a2713aSLionel Sambuc   if (Known != CanonicalDirNames.end())
552f4a2713aSLionel Sambuc     return Known->second;
553f4a2713aSLionel Sambuc 
554f4a2713aSLionel Sambuc   StringRef CanonicalName(Dir->getName());
555*0a6a1f1dSLionel Sambuc 
556*0a6a1f1dSLionel Sambuc #ifdef LLVM_ON_UNIX
557f4a2713aSLionel Sambuc   char CanonicalNameBuf[PATH_MAX];
558f4a2713aSLionel Sambuc   if (realpath(Dir->getName(), CanonicalNameBuf)) {
559f4a2713aSLionel Sambuc     unsigned Len = strlen(CanonicalNameBuf);
560f4a2713aSLionel Sambuc     char *Mem = static_cast<char *>(CanonicalNameStorage.Allocate(Len, 1));
561f4a2713aSLionel Sambuc     memcpy(Mem, CanonicalNameBuf, Len);
562f4a2713aSLionel Sambuc     CanonicalName = StringRef(Mem, Len);
563f4a2713aSLionel Sambuc   }
564*0a6a1f1dSLionel Sambuc #else
565*0a6a1f1dSLionel Sambuc   SmallString<256> CanonicalNameBuf(CanonicalName);
566*0a6a1f1dSLionel Sambuc   llvm::sys::fs::make_absolute(CanonicalNameBuf);
567*0a6a1f1dSLionel Sambuc   llvm::sys::path::native(CanonicalNameBuf);
568*0a6a1f1dSLionel Sambuc   removeDotPaths(CanonicalNameBuf);
569*0a6a1f1dSLionel Sambuc #endif
570f4a2713aSLionel Sambuc 
571f4a2713aSLionel Sambuc   CanonicalDirNames.insert(std::make_pair(Dir, CanonicalName));
572f4a2713aSLionel Sambuc   return CanonicalName;
573f4a2713aSLionel Sambuc }
574f4a2713aSLionel Sambuc 
PrintStats() const575f4a2713aSLionel Sambuc void FileManager::PrintStats() const {
576f4a2713aSLionel Sambuc   llvm::errs() << "\n*** File Manager Stats:\n";
577f4a2713aSLionel Sambuc   llvm::errs() << UniqueRealFiles.size() << " real files found, "
578f4a2713aSLionel Sambuc                << UniqueRealDirs.size() << " real dirs found.\n";
579f4a2713aSLionel Sambuc   llvm::errs() << VirtualFileEntries.size() << " virtual files found, "
580f4a2713aSLionel Sambuc                << VirtualDirectoryEntries.size() << " virtual dirs found.\n";
581f4a2713aSLionel Sambuc   llvm::errs() << NumDirLookups << " dir lookups, "
582f4a2713aSLionel Sambuc                << NumDirCacheMisses << " dir cache misses.\n";
583f4a2713aSLionel Sambuc   llvm::errs() << NumFileLookups << " file lookups, "
584f4a2713aSLionel Sambuc                << NumFileCacheMisses << " file cache misses.\n";
585f4a2713aSLionel Sambuc 
586f4a2713aSLionel Sambuc   //llvm::errs() << PagesMapped << BytesOfPagesMapped << FSLookups;
587f4a2713aSLionel Sambuc }
588