Clang Project

clang_source_code/lib/Basic/FileManager.cpp
1//===--- FileManager.cpp - File System Probing and Caching ----------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9//  This file implements the FileManager interface.
10//
11//===----------------------------------------------------------------------===//
12//
13// TODO: This should index all interesting directories with dirent calls.
14//  getdirentries ?
15//  opendir/readdir_r/closedir ?
16//
17//===----------------------------------------------------------------------===//
18
19#include "clang/Basic/FileManager.h"
20#include "clang/Basic/FileSystemStatCache.h"
21#include "llvm/ADT/SmallString.h"
22#include "llvm/Config/llvm-config.h"
23#include "llvm/ADT/STLExtras.h"
24#include "llvm/Support/FileSystem.h"
25#include "llvm/Support/MemoryBuffer.h"
26#include "llvm/Support/Path.h"
27#include "llvm/Support/raw_ostream.h"
28#include <algorithm>
29#include <cassert>
30#include <climits>
31#include <cstdint>
32#include <cstdlib>
33#include <string>
34#include <utility>
35
36using namespace clang;
37
38//===----------------------------------------------------------------------===//
39// Common logic.
40//===----------------------------------------------------------------------===//
41
42FileManager::FileManager(const FileSystemOptions &FSO,
43                         IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)
44    : FS(std::move(FS)), FileSystemOpts(FSO), SeenDirEntries(64),
45      SeenFileEntries(64), NextFileUID(0) {
46  NumDirLookups = NumFileLookups = 0;
47  NumDirCacheMisses = NumFileCacheMisses = 0;
48
49  // If the caller doesn't provide a virtual file system, just grab the real
50  // file system.
51  if (!this->FS)
52    this->FS = llvm::vfs::getRealFileSystem();
53}
54
55FileManager::~FileManager() = default;
56
57void FileManager::setStatCache(std::unique_ptr<FileSystemStatCachestatCache) {
58   (0) . __assert_fail ("statCache && \"No stat cache provided?\"", "/home/seafit/code_projects/clang_source/clang/lib/Basic/FileManager.cpp", 58, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(statCache && "No stat cache provided?");
59  StatCache = std::move(statCache);
60}
61
62void FileManager::clearStatCache() { StatCache.reset(); }
63
64/// Retrieve the directory that the given file name resides in.
65/// Filename can point to either a real file or a virtual file.
66static const DirectoryEntry *getDirectoryFromFile(FileManager &FileMgr,
67                                                  StringRef Filename,
68                                                  bool CacheFailure) {
69  if (Filename.empty())
70    return nullptr;
71
72  if (llvm::sys::path::is_separator(Filename[Filename.size() - 1]))
73    return nullptr// If Filename is a directory.
74
75  StringRef DirName = llvm::sys::path::parent_path(Filename);
76  // Use the current directory if file has no path component.
77  if (DirName.empty())
78    DirName = ".";
79
80  return FileMgr.getDirectory(DirName, CacheFailure);
81}
82
83/// Add all ancestors of the given path (pointing to either a file or
84/// a directory) as virtual directories.
85void FileManager::addAncestorsAsVirtualDirs(StringRef Path) {
86  StringRef DirName = llvm::sys::path::parent_path(Path);
87  if (DirName.empty())
88    DirName = ".";
89
90  auto &NamedDirEnt = *SeenDirEntries.insert({DirName, nullptr}).first;
91
92  // When caching a virtual directory, we always cache its ancestors
93  // at the same time.  Therefore, if DirName is already in the cache,
94  // we don't need to recurse as its ancestors must also already be in
95  // the cache (or it's a known non-virtual directory).
96  if (NamedDirEnt.second)
97    return;
98
99  // Add the virtual directory to the cache.
100  auto UDE = llvm::make_unique<DirectoryEntry>();
101  UDE->Name = NamedDirEnt.first();
102  NamedDirEnt.second = UDE.get();
103  VirtualDirectoryEntries.push_back(std::move(UDE));
104
105  // Recursively add the other ancestors.
106  addAncestorsAsVirtualDirs(DirName);
107}
108
109const DirectoryEntry *FileManager::getDirectory(StringRef DirName,
110                                                bool CacheFailure) {
111  // stat doesn't like trailing separators except for root directory.
112  // At least, on Win32 MSVCRT, stat() cannot strip trailing '/'.
113  // (though it can strip '\\')
114  if (DirName.size() > 1 &&
115      DirName != llvm::sys::path::root_path(DirName) &&
116      llvm::sys::path::is_separator(DirName.back()))
117    DirName = DirName.substr(0, DirName.size()-1);
118#ifdef _WIN32
119  // Fixing a problem with "clang C:test.c" on Windows.
120  // Stat("C:") does not recognize "C:" as a valid directory
121  std::string DirNameStr;
122  if (DirName.size() > 1 && DirName.back() == ':' &&
123      DirName.equals_lower(llvm::sys::path::root_name(DirName))) {
124    DirNameStr = DirName.str() + '.';
125    DirName = DirNameStr;
126  }
127#endif
128
129  ++NumDirLookups;
130
131  // See if there was already an entry in the map.  Note that the map
132  // contains both virtual and real directories.
133  auto SeenDirInsertResult = SeenDirEntries.insert({DirName, nullptr});
134  if (!SeenDirInsertResult.second)
135    return SeenDirInsertResult.first->second;
136
137  // We've not seen this before. Fill it in.
138  ++NumDirCacheMisses;
139  auto &NamedDirEnt = *SeenDirInsertResult.first;
140   (0) . __assert_fail ("!NamedDirEnt.second && \"should be newly-created\"", "/home/seafit/code_projects/clang_source/clang/lib/Basic/FileManager.cpp", 140, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(!NamedDirEnt.second && "should be newly-created");
141
142  // Get the null-terminated directory name as stored as the key of the
143  // SeenDirEntries map.
144  StringRef InterndDirName = NamedDirEnt.first();
145
146  // Check to see if the directory exists.
147  llvm::vfs::Status Status;
148  if (getStatValue(InterndDirName, Status, falsenullptr /*directory lookup*/)) {
149    // There's no real directory at the given path.
150    if (!CacheFailure)
151      SeenDirEntries.erase(DirName);
152    return nullptr;
153  }
154
155  // It exists.  See if we have already opened a directory with the
156  // same inode (this occurs on Unix-like systems when one dir is
157  // symlinked to another, for example) or the same path (on
158  // Windows).
159  DirectoryEntry &UDE = UniqueRealDirs[Status.getUniqueID()];
160
161  NamedDirEnt.second = &UDE;
162  if (UDE.getName().empty()) {
163    // We don't have this directory yet, add it.  We use the string
164    // key from the SeenDirEntries map as the string.
165    UDE.Name  = InterndDirName;
166  }
167
168  return &UDE;
169}
170
171const FileEntry *FileManager::getFile(StringRef Filenamebool openFile,
172                                      bool CacheFailure) {
173  ++NumFileLookups;
174
175  // See if there is already an entry in the map.
176  auto SeenFileInsertResult = SeenFileEntries.insert({Filename, nullptr});
177  if (!SeenFileInsertResult.second)
178    return SeenFileInsertResult.first->second;
179
180  // We've not seen this before. Fill it in.
181  ++NumFileCacheMisses;
182  auto &NamedFileEnt = *SeenFileInsertResult.first;
183   (0) . __assert_fail ("!NamedFileEnt.second && \"should be newly-created\"", "/home/seafit/code_projects/clang_source/clang/lib/Basic/FileManager.cpp", 183, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(!NamedFileEnt.second && "should be newly-created");
184
185  // Get the null-terminated file name as stored as the key of the
186  // SeenFileEntries map.
187  StringRef InterndFileName = NamedFileEnt.first();
188
189  // Look up the directory for the file.  When looking up something like
190  // sys/foo.h we'll discover all of the search directories that have a 'sys'
191  // subdirectory.  This will let us avoid having to waste time on known-to-fail
192  // searches when we go to find sys/bar.h, because all the search directories
193  // without a 'sys' subdir will get a cached failure result.
194  const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename,
195                                                       CacheFailure);
196  if (DirInfo == nullptr) { // Directory doesn't exist, file can't exist.
197    if (!CacheFailure)
198      SeenFileEntries.erase(Filename);
199
200    return nullptr;
201  }
202
203  // FIXME: Use the directory info to prune this, before doing the stat syscall.
204  // FIXME: This will reduce the # syscalls.
205
206  // Check to see if the file exists.
207  std::unique_ptr<llvm::vfs::File> F;
208  llvm::vfs::Status Status;
209  if (getStatValue(InterndFileName, Status, true, openFile ? &F : nullptr)) {
210    // There's no real file at the given path.
211    if (!CacheFailure)
212      SeenFileEntries.erase(Filename);
213
214    return nullptr;
215  }
216
217   (0) . __assert_fail ("(openFile || !F) && \"undesired open file\"", "/home/seafit/code_projects/clang_source/clang/lib/Basic/FileManager.cpp", 217, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert((openFile || !F) && "undesired open file");
218
219  // It exists.  See if we have already opened a file with the same inode.
220  // This occurs when one dir is symlinked to another, for example.
221  FileEntry &UFE = UniqueRealFiles[Status.getUniqueID()];
222
223  NamedFileEnt.second = &UFE;
224
225  // If the name returned by getStatValue is different than Filename, re-intern
226  // the name.
227  if (Status.getName() != Filename) {
228    auto &NamedFileEnt =
229      *SeenFileEntries.insert({Status.getName(), &UFE}).first;
230     (0) . __assert_fail ("NamedFileEnt.second == &UFE && \"filename from getStatValue() refers to wrong file\"", "/home/seafit/code_projects/clang_source/clang/lib/Basic/FileManager.cpp", 231, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(NamedFileEnt.second == &UFE &&
231 (0) . __assert_fail ("NamedFileEnt.second == &UFE && \"filename from getStatValue() refers to wrong file\"", "/home/seafit/code_projects/clang_source/clang/lib/Basic/FileManager.cpp", 231, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">           "filename from getStatValue() refers to wrong file");
232    InterndFileName = NamedFileEnt.first().data();
233  }
234
235  if (UFE.isValid()) { // Already have an entry with this inode, return it.
236
237    // FIXME: this hack ensures that if we look up a file by a virtual path in
238    // the VFS that the getDir() will have the virtual path, even if we found
239    // the file by a 'real' path first. This is required in order to find a
240    // module's structure when its headers/module map are mapped in the VFS.
241    // We should remove this as soon as we can properly support a file having
242    // multiple names.
243    if (DirInfo != UFE.Dir && Status.IsVFSMapped)
244      UFE.Dir = DirInfo;
245
246    // Always update the name to use the last name by which a file was accessed.
247    // FIXME: Neither this nor always using the first name is correct; we want
248    // to switch towards a design where we return a FileName object that
249    // encapsulates both the name by which the file was accessed and the
250    // corresponding FileEntry.
251    UFE.Name = InterndFileName;
252
253    return &UFE;
254  }
255
256  // Otherwise, we don't have this file yet, add it.
257  UFE.Name    = InterndFileName;
258  UFE.Size    = Status.getSize();
259  UFE.ModTime = llvm::sys::toTimeT(Status.getLastModificationTime());
260  UFE.Dir     = DirInfo;
261  UFE.UID     = NextFileUID++;
262  UFE.UniqueID = Status.getUniqueID();
263  UFE.IsNamedPipe = Status.getType() == llvm::sys::fs::file_type::fifo_file;
264  UFE.File = std::move(F);
265  UFE.IsValid = true;
266
267  if (UFE.File) {
268    if (auto PathName = UFE.File->getName())
269      fillRealPathName(&UFE, *PathName);
270  } else if (!openFile) {
271    // We should still fill the path even if we aren't opening the file.
272    fillRealPathName(&UFE, InterndFileName);
273  }
274  return &UFE;
275}
276
277const FileEntry *
278FileManager::getVirtualFile(StringRef Filenameoff_t Size,
279                            time_t ModificationTime) {
280  ++NumFileLookups;
281
282  // See if there is already an entry in the map for an existing file.
283  auto &NamedFileEnt = *SeenFileEntries.insert({Filename, nullptr}).first;
284  if (NamedFileEnt.second)
285    return NamedFileEnt.second;
286
287  // We've not seen this before, or the file is cached as non-existent.
288  ++NumFileCacheMisses;
289  addAncestorsAsVirtualDirs(Filename);
290  FileEntry *UFE = nullptr;
291
292  // Now that all ancestors of Filename are in the cache, the
293  // following call is guaranteed to find the DirectoryEntry from the
294  // cache.
295  const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename,
296                                                       /*CacheFailure=*/true);
297   (0) . __assert_fail ("DirInfo && \"The directory of a virtual file should already be in the cache.\"", "/home/seafit/code_projects/clang_source/clang/lib/Basic/FileManager.cpp", 298, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(DirInfo &&
298 (0) . __assert_fail ("DirInfo && \"The directory of a virtual file should already be in the cache.\"", "/home/seafit/code_projects/clang_source/clang/lib/Basic/FileManager.cpp", 298, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">         "The directory of a virtual file should already be in the cache.");
299
300  // Check to see if the file exists. If so, drop the virtual file
301  llvm::vfs::Status Status;
302  const char *InterndFileName = NamedFileEnt.first().data();
303  if (getStatValue(InterndFileName, Status, truenullptr) == 0) {
304    UFE = &UniqueRealFiles[Status.getUniqueID()];
305    Status = llvm::vfs::Status(
306      Status.getName(), Status.getUniqueID(),
307      llvm::sys::toTimePoint(ModificationTime),
308      Status.getUser(), Status.getGroup(), Size,
309      Status.getType(), Status.getPermissions());
310
311    NamedFileEnt.second = UFE;
312
313    // If we had already opened this file, close it now so we don't
314    // leak the descriptor. We're not going to use the file
315    // descriptor anyway, since this is a virtual file.
316    if (UFE->File)
317      UFE->closeFile();
318
319    // If we already have an entry with this inode, return it.
320    if (UFE->isValid())
321      return UFE;
322
323    UFE->UniqueID = Status.getUniqueID();
324    UFE->IsNamedPipe = Status.getType() == llvm::sys::fs::file_type::fifo_file;
325    fillRealPathName(UFE, Status.getName());
326  } else {
327    VirtualFileEntries.push_back(llvm::make_unique<FileEntry>());
328    UFE = VirtualFileEntries.back().get();
329    NamedFileEnt.second = UFE;
330  }
331
332  UFE->Name    = InterndFileName;
333  UFE->Size    = Size;
334  UFE->ModTime = ModificationTime;
335  UFE->Dir     = DirInfo;
336  UFE->UID     = NextFileUID++;
337  UFE->IsValid = true;
338  UFE->File.reset();
339  return UFE;
340}
341
342bool FileManager::FixupRelativePath(SmallVectorImpl<char> &pathconst {
343  StringRef pathRef(path.data(), path.size());
344
345  if (FileSystemOpts.WorkingDir.empty()
346      || llvm::sys::path::is_absolute(pathRef))
347    return false;
348
349  SmallString<128NewPath(FileSystemOpts.WorkingDir);
350  llvm::sys::path::append(NewPath, pathRef);
351  path = NewPath;
352  return true;
353}
354
355bool FileManager::makeAbsolutePath(SmallVectorImpl<char> &Pathconst {
356  bool Changed = FixupRelativePath(Path);
357
358  if (!llvm::sys::path::is_absolute(StringRef(Path.data(), Path.size()))) {
359    FS->makeAbsolute(Path);
360    Changed = true;
361  }
362
363  return Changed;
364}
365
366void FileManager::fillRealPathName(FileEntry *UFEllvm::StringRef FileName) {
367  llvm::SmallString<128AbsPath(FileName);
368  // This is not the same as `VFS::getRealPath()`, which resolves symlinks
369  // but can be very expensive on real file systems.
370  // FIXME: the semantic of RealPathName is unclear, and the name might be
371  // misleading. We need to clean up the interface here.
372  makeAbsolutePath(AbsPath);
373  llvm::sys::path::remove_dots(AbsPath, /*remove_dot_dot=*/true);
374  UFE->RealPathName = AbsPath.str();
375}
376
377llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
378FileManager::getBufferForFile(const FileEntry *Entry, bool isVolatile,
379                              bool ShouldCloseOpenFile) {
380  uint64_t FileSize = Entry->getSize();
381  // If there's a high enough chance that the file have changed since we
382  // got its size, force a stat before opening it.
383  if (isVolatile)
384    FileSize = -1;
385
386  StringRef Filename = Entry->getName();
387  // If the file is already open, use the open file descriptor.
388  if (Entry->File) {
389    auto Result =
390        Entry->File->getBuffer(Filename, FileSize,
391                               /*RequiresNullTerminator=*/true, isVolatile);
392    // FIXME: we need a set of APIs that can make guarantees about whether a
393    // FileEntry is open or not.
394    if (ShouldCloseOpenFile)
395      Entry->closeFile();
396    return Result;
397  }
398
399  // Otherwise, open the file.
400
401  if (FileSystemOpts.WorkingDir.empty())
402    return FS->getBufferForFile(Filename, FileSize,
403                                /*RequiresNullTerminator=*/true, isVolatile);
404
405  SmallString<128FilePath(Entry->getName());
406  FixupRelativePath(FilePath);
407  return FS->getBufferForFile(FilePath, FileSize,
408                              /*RequiresNullTerminator=*/true, isVolatile);
409}
410
411llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
412FileManager::getBufferForFile(StringRef Filename, bool isVolatile) {
413  if (FileSystemOpts.WorkingDir.empty())
414    return FS->getBufferForFile(Filename, -1true, isVolatile);
415
416  SmallString<128FilePath(Filename);
417  FixupRelativePath(FilePath);
418  return FS->getBufferForFile(FilePath.c_str(), -1true, isVolatile);
419}
420
421/// getStatValue - Get the 'stat' information for the specified path,
422/// using the cache to accelerate it if possible.  This returns true
423/// if the path points to a virtual file or does not exist, or returns
424/// false if it's an existent real file.  If FileDescriptor is NULL,
425/// do directory look-up instead of file look-up.
426bool FileManager::getStatValue(StringRef Path, llvm::vfs::Status &Status,
427                               bool isFile,
428                               std::unique_ptr<llvm::vfs::File> *F) {
429  // FIXME: FileSystemOpts shouldn't be passed in here, all paths should be
430  // absolute!
431  if (FileSystemOpts.WorkingDir.empty())
432    return FileSystemStatCache::get(Path, Status, isFile, F,StatCache.get(), *FS);
433
434  SmallString<128FilePath(Path);
435  FixupRelativePath(FilePath);
436
437  return FileSystemStatCache::get(FilePath.c_str(), Status, isFile, F,
438                                  StatCache.get(), *FS);
439}
440
441bool FileManager::getNoncachedStatValue(StringRef Path,
442                                        llvm::vfs::Status &Result) {
443  SmallString<128FilePath(Path);
444  FixupRelativePath(FilePath);
445
446  llvm::ErrorOr<llvm::vfs::Status> S = FS->status(FilePath.c_str());
447  if (!S)
448    return true;
449  Result = *S;
450  return false;
451}
452
453void FileManager::invalidateCache(const FileEntry *Entry) {
454   (0) . __assert_fail ("Entry && \"Cannot invalidate a NULL FileEntry\"", "/home/seafit/code_projects/clang_source/clang/lib/Basic/FileManager.cpp", 454, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Entry && "Cannot invalidate a NULL FileEntry");
455
456  SeenFileEntries.erase(Entry->getName());
457
458  // FileEntry invalidation should not block future optimizations in the file
459  // caches. Possible alternatives are cache truncation (invalidate last N) or
460  // invalidation of the whole cache.
461  //
462  // FIXME: This is broken. We sometimes have the same FileEntry* shared
463  // betweeen multiple SeenFileEntries, so this can leave dangling pointers.
464  UniqueRealFiles.erase(Entry->getUniqueID());
465}
466
467void FileManager::GetUniqueIDMapping(
468                   SmallVectorImpl<const FileEntry *> &UIDToFilesconst {
469  UIDToFiles.clear();
470  UIDToFiles.resize(NextFileUID);
471
472  // Map file entries
473  for (llvm::StringMap<FileEntry*, llvm::BumpPtrAllocator>::const_iterator
474         FE = SeenFileEntries.begin(), FEEnd = SeenFileEntries.end();
475       FE != FEEnd; ++FE)
476    if (FE->getValue())
477      UIDToFiles[FE->getValue()->getUID()] = FE->getValue();
478
479  // Map virtual file entries
480  for (const auto &VFE : VirtualFileEntries)
481    UIDToFiles[VFE->getUID()] = VFE.get();
482}
483
484void FileManager::modifyFileEntry(FileEntry *File,
485                                  off_t Sizetime_t ModificationTime) {
486  File->Size = Size;
487  File->ModTime = ModificationTime;
488}
489
490StringRef FileManager::getCanonicalName(const DirectoryEntry *Dir) {
491  // FIXME: use llvm::sys::fs::canonical() when it gets implemented
492  llvm::DenseMap<const DirectoryEntry *, llvm::StringRef>::iterator Known
493    = CanonicalDirNames.find(Dir);
494  if (Known != CanonicalDirNames.end())
495    return Known->second;
496
497  StringRef CanonicalName(Dir->getName());
498
499  SmallString<4096CanonicalNameBuf;
500  if (!FS->getRealPath(Dir->getName(), CanonicalNameBuf))
501    CanonicalName = StringRef(CanonicalNameBuf).copy(CanonicalNameStorage);
502
503  CanonicalDirNames.insert({Dir, CanonicalName});
504  return CanonicalName;
505}
506
507void FileManager::PrintStats() const {
508  llvm::errs() << "\n*** File Manager Stats:\n";
509  llvm::errs() << UniqueRealFiles.size() << " real files found, "
510               << UniqueRealDirs.size() << " real dirs found.\n";
511  llvm::errs() << VirtualFileEntries.size() << " virtual files found, "
512               << VirtualDirectoryEntries.size() << " virtual dirs found.\n";
513  llvm::errs() << NumDirLookups << " dir lookups, "
514               << NumDirCacheMisses << " dir cache misses.\n";
515  llvm::errs() << NumFileLookups << " file lookups, "
516               << NumFileCacheMisses << " file cache misses.\n";
517
518  //llvm::errs() << PagesMapped << BytesOfPagesMapped << FSLookups;
519}
520
clang::FileManager::setStatCache
clang::FileManager::clearStatCache
clang::FileManager::addAncestorsAsVirtualDirs
clang::FileManager::getDirectory
clang::FileManager::getFile
clang::FileManager::getVirtualFile
clang::FileManager::FixupRelativePath
clang::FileManager::makeAbsolutePath
clang::FileManager::fillRealPathName
clang::FileManager::getBufferForFile
clang::FileManager::getBufferForFile
clang::FileManager::getStatValue
clang::FileManager::getNoncachedStatValue
clang::FileManager::invalidateCache
clang::FileManager::GetUniqueIDMapping
clang::FileManager::modifyFileEntry
clang::FileManager::getCanonicalName
clang::FileManager::PrintStats