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