FileManager.cpp revision f69a1f319bd3c846c4a9ab84ea615e4e37dfd359
18fbc88e5faee291e2e5039ec4c1dac3cfd219704Ted Kremenek///===--- FileManager.cpp - File System Probing and Caching ----------------===//
25f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//
35f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//                     The LLVM Compiler Infrastructure
45f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//
50bc735ffcfb223c0186419547abaa5c84482663eChris Lattner// This file is distributed under the University of Illinois Open Source
60bc735ffcfb223c0186419547abaa5c84482663eChris Lattner// License. See LICENSE.TXT for details.
75f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//
85f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//===----------------------------------------------------------------------===//
95f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//
105f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//  This file implements the FileManager interface.
115f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//
125f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//===----------------------------------------------------------------------===//
135f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//
145f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// TODO: This should index all interesting directories with dirent calls.
155f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//  getdirentries ?
165f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//  opendir/readdir_r/closedir ?
175f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//
185f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//===----------------------------------------------------------------------===//
195f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
205f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer#include "clang/Basic/FileManager.h"
21389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis#include "clang/Basic/FileSystemOptions.h"
225f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer#include "llvm/ADT/SmallString.h"
23c070da46b896940aa2cbac416e5a2f8eee22d7d8Chris Lattner#include "llvm/ADT/StringExtras.h"
24389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis#include "llvm/Support/MemoryBuffer.h"
25d57a7ef9252964bc6c8471451d7bd395b0520cb8Chris Lattner#include "llvm/Support/raw_ostream.h"
264fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor#include "llvm/System/Path.h"
276bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek#include "llvm/Config/config.h"
28458fb10ef5ba2d7b375c6c64095c1458af0a5be3Benjamin Kramer#include <map>
29458fb10ef5ba2d7b375c6c64095c1458af0a5be3Benjamin Kramer#include <set>
30458fb10ef5ba2d7b375c6c64095c1458af0a5be3Benjamin Kramer#include <string>
315f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencerusing namespace clang;
325f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
335f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// FIXME: Enhance libsystem to support inode and other fields.
345f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer#include <sys/stat.h>
355f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
36a8c11c6a7831df37f2f40b34072360b04f6d19a8Chris Lattner#if defined(_MSC_VER)
373102c83f6eac0cbbd698471173672c3e47a6914cChris Lattner#define S_ISDIR(s) (_S_IFDIR & s)
38a8c11c6a7831df37f2f40b34072360b04f6d19a8Chris Lattner#endif
395f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
403d2da3d765123e15290c38ba44f4434462bb88d5Ted Kremenek/// NON_EXISTENT_DIR - A special value distinct from null that is used to
415f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// represent a dir name that doesn't exist on the disk.
423d2da3d765123e15290c38ba44f4434462bb88d5Ted Kremenek#define NON_EXISTENT_DIR reinterpret_cast<DirectoryEntry*>((intptr_t)-1)
435f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
44cb8d58b82859d2c56b679b901de38f416e2b6f48Ted Kremenek//===----------------------------------------------------------------------===//
45cb8d58b82859d2c56b679b901de38f416e2b6f48Ted Kremenek// Windows.
46cb8d58b82859d2c56b679b901de38f416e2b6f48Ted Kremenek//===----------------------------------------------------------------------===//
47cb8d58b82859d2c56b679b901de38f416e2b6f48Ted Kremenek
486bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek#ifdef LLVM_ON_WIN32
496bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
50f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris Lattner#define DIR_SEPARATOR_CHARS "/\\"
516bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
526bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremeneknamespace {
531eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  static std::string GetFullPath(const char *relPath) {
546bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek    char *absPathStrPtr = _fullpath(NULL, relPath, 0);
556bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek    assert(absPathStrPtr && "_fullpath() returned NULL!");
566bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
576bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek    std::string absPath(absPathStrPtr);
586bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
596bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek    free(absPathStrPtr);
606bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek    return absPath;
616bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  }
626bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek}
636bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
646bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenekclass FileManager::UniqueDirContainer {
656bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  /// UniqueDirs - Cache from full path to existing directories/files.
666bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  ///
671eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  llvm::StringMap<DirectoryEntry> UniqueDirs;
686bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
696bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenekpublic:
706bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  DirectoryEntry &getDirectory(const char *Name, struct stat &StatBuf) {
716bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek    std::string FullPath(GetFullPath(Name));
726bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek    return UniqueDirs.GetOrCreateValue(
736bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek                              FullPath.c_str(),
746bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek                              FullPath.c_str() + FullPath.size()
756bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek                                                                ).getValue();
766bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  }
771eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
786bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  size_t size() { return UniqueDirs.size(); }
796bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek};
806bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
816bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenekclass FileManager::UniqueFileContainer {
826bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  /// UniqueFiles - Cache from full path to existing directories/files.
836bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  ///
8475368893339d89f6523c312b0a0eb23d438b6dffTed Kremenek  llvm::StringMap<FileEntry, llvm::BumpPtrAllocator> UniqueFiles;
856bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
866bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenekpublic:
876bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  FileEntry &getFile(const char *Name, struct stat &StatBuf) {
886bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek    std::string FullPath(GetFullPath(Name));
89c070da46b896940aa2cbac416e5a2f8eee22d7d8Chris Lattner
90c070da46b896940aa2cbac416e5a2f8eee22d7d8Chris Lattner    // LowercaseString because Windows filesystem is case insensitive.
91c070da46b896940aa2cbac416e5a2f8eee22d7d8Chris Lattner    FullPath = llvm::LowercaseString(FullPath);
926bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek    return UniqueFiles.GetOrCreateValue(
936bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek                               FullPath.c_str(),
946bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek                               FullPath.c_str() + FullPath.size()
956bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek                                                                 ).getValue();
966bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  }
976bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
986bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  size_t size() { return UniqueFiles.size(); }
996bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek};
1006bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
101cb8d58b82859d2c56b679b901de38f416e2b6f48Ted Kremenek//===----------------------------------------------------------------------===//
102cb8d58b82859d2c56b679b901de38f416e2b6f48Ted Kremenek// Unix-like Systems.
103cb8d58b82859d2c56b679b901de38f416e2b6f48Ted Kremenek//===----------------------------------------------------------------------===//
104cb8d58b82859d2c56b679b901de38f416e2b6f48Ted Kremenek
1056bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek#else
1066bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
107f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris Lattner#define DIR_SEPARATOR_CHARS "/"
1086bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
1096bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenekclass FileManager::UniqueDirContainer {
1106bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  /// UniqueDirs - Cache from ID's to existing directories/files.
1116bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  ///
1121eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  std::map<std::pair<dev_t, ino_t>, DirectoryEntry> UniqueDirs;
1136bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
1146bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenekpublic:
1156bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  DirectoryEntry &getDirectory(const char *Name, struct stat &StatBuf) {
1166bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek    return UniqueDirs[std::make_pair(StatBuf.st_dev, StatBuf.st_ino)];
1176bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  }
1186bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
1196bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  size_t size() { return UniqueDirs.size(); }
1206bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek};
1216bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
1226bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenekclass FileManager::UniqueFileContainer {
1236bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  /// UniqueFiles - Cache from ID's to existing directories/files.
1246bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  ///
1256bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  std::set<FileEntry> UniqueFiles;
1266bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
1276bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenekpublic:
1286bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  FileEntry &getFile(const char *Name, struct stat &StatBuf) {
1296bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek    return
1306bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek      const_cast<FileEntry&>(
1316bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek                    *UniqueFiles.insert(FileEntry(StatBuf.st_dev,
13296438f319bb07d9a40564b5e01333f82c0c8a61eTed Kremenek                                                  StatBuf.st_ino,
13396438f319bb07d9a40564b5e01333f82c0c8a61eTed Kremenek                                                  StatBuf.st_mode)).first);
1346bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  }
1356bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
1366bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  size_t size() { return UniqueFiles.size(); }
1376bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek};
1386bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
1396bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek#endif
1406bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
141cb8d58b82859d2c56b679b901de38f416e2b6f48Ted Kremenek//===----------------------------------------------------------------------===//
142cb8d58b82859d2c56b679b901de38f416e2b6f48Ted Kremenek// Common logic.
143cb8d58b82859d2c56b679b901de38f416e2b6f48Ted Kremenek//===----------------------------------------------------------------------===//
1446bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
14596438f319bb07d9a40564b5e01333f82c0c8a61eTed KremenekFileManager::FileManager()
146fc7052d4a241ee6fc70afea7c1c9560147f0a49cTed Kremenek  : UniqueDirs(*new UniqueDirContainer),
147fc7052d4a241ee6fc70afea7c1c9560147f0a49cTed Kremenek    UniqueFiles(*new UniqueFileContainer),
14896438f319bb07d9a40564b5e01333f82c0c8a61eTed Kremenek    DirEntries(64), FileEntries(64), NextFileUID(0) {
1496bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  NumDirLookups = NumFileLookups = 0;
1506bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  NumDirCacheMisses = NumFileCacheMisses = 0;
1516bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek}
1526bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
1536bb816a3b895e9c983d89b22d510dca58a0eb75eTed KremenekFileManager::~FileManager() {
1546bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  delete &UniqueDirs;
1556bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  delete &UniqueFiles;
156057e567f1b375190779e5341f42861896cdee442Douglas Gregor  for (llvm::SmallVectorImpl<FileEntry *>::iterator
157057e567f1b375190779e5341f42861896cdee442Douglas Gregor         V = VirtualFileEntries.begin(),
158057e567f1b375190779e5341f42861896cdee442Douglas Gregor         VEnd = VirtualFileEntries.end();
159057e567f1b375190779e5341f42861896cdee442Douglas Gregor       V != VEnd;
160057e567f1b375190779e5341f42861896cdee442Douglas Gregor       ++V)
161057e567f1b375190779e5341f42861896cdee442Douglas Gregor    delete *V;
1626bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek}
1636bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
16452e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregorvoid FileManager::addStatCache(StatSysCallCache *statCache, bool AtBeginning) {
16552e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor  assert(statCache && "No stat cache provided?");
16652e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor  if (AtBeginning || StatCache.get() == 0) {
16752e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor    statCache->setNextStatCache(StatCache.take());
16852e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor    StatCache.reset(statCache);
16952e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor    return;
17052e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor  }
17152e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor
17252e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor  StatSysCallCache *LastCache = StatCache.get();
17352e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor  while (LastCache->getNextStatCache())
17452e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor    LastCache = LastCache->getNextStatCache();
17552e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor
17652e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor  LastCache->setNextStatCache(statCache);
17752e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor}
17852e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor
17952e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregorvoid FileManager::removeStatCache(StatSysCallCache *statCache) {
18052e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor  if (!statCache)
18152e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor    return;
18252e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor
18352e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor  if (StatCache.get() == statCache) {
18452e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor    // This is the first stat cache.
18552e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor    StatCache.reset(StatCache->takeNextStatCache());
18652e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor    return;
18752e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor  }
18852e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor
18952e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor  // Find the stat cache in the list.
19052e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor  StatSysCallCache *PrevCache = StatCache.get();
19152e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor  while (PrevCache && PrevCache->getNextStatCache() != statCache)
19252e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor    PrevCache = PrevCache->getNextStatCache();
19352e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor  if (PrevCache)
19452e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor    PrevCache->setNextStatCache(statCache->getNextStatCache());
19552e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor  else
19652e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor    assert(false && "Stat cache not found for removal");
19752e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor}
19852e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor
199057e567f1b375190779e5341f42861896cdee442Douglas Gregor/// \brief Retrieve the directory that the given file name resides in.
200057e567f1b375190779e5341f42861896cdee442Douglas Gregorstatic const DirectoryEntry *getDirectoryFromFile(FileManager &FileMgr,
201f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris Lattner                                                  llvm::StringRef Filename,
202389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis                                      const FileSystemOptions &FileSystemOpts) {
203057e567f1b375190779e5341f42861896cdee442Douglas Gregor  // Figure out what directory it is in.   If the string contains a / in it,
204057e567f1b375190779e5341f42861896cdee442Douglas Gregor  // strip off everything after it.
205057e567f1b375190779e5341f42861896cdee442Douglas Gregor  // FIXME: this logic should be in sys::Path.
206f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris Lattner  size_t SlashPos = Filename.rfind(DIR_SEPARATOR_CHARS);
207f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris Lattner
208f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris Lattner  // Use the current directory if file has no path component.
209f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris Lattner  if (SlashPos == llvm::StringRef::npos)
210f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris Lattner    return FileMgr.getDirectory(".", FileSystemOpts);
211057e567f1b375190779e5341f42861896cdee442Douglas Gregor
212f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris Lattner  if (SlashPos == Filename.size()-1)
213057e567f1b375190779e5341f42861896cdee442Douglas Gregor    return 0;       // If filename ends with a /, it's a directory.
214f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris Lattner
215f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris Lattner  // Ignore repeated //'s.
216f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris Lattner  while (SlashPos != 0 &&
217f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris Lattner         llvm::StringRef(DIR_SEPARATOR_CHARS).count(Filename[SlashPos-1]))
218f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris Lattner    --SlashPos;
219f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris Lattner
220f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris Lattner  return FileMgr.getDirectory(Filename.substr(0, SlashPos), FileSystemOpts);
221057e567f1b375190779e5341f42861896cdee442Douglas Gregor}
222057e567f1b375190779e5341f42861896cdee442Douglas Gregor
2235f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// getDirectory - Lookup, cache, and verify the specified directory.  This
2245f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// returns null if the directory doesn't exist.
2251eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump///
226f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris Lattnerconst DirectoryEntry *FileManager::getDirectory(llvm::StringRef Filename,
227389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis                                      const FileSystemOptions &FileSystemOpts) {
2289a6ac540bab63380a4a78d8fad87f23c50878685John Thompson  // stat doesn't like trailing separators (at least on Windows).
229f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris Lattner  if (Filename.size() > 1 &&
230f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris Lattner      (Filename.back() == '/' || Filename.back() == '\\'))
231f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris Lattner    Filename = Filename.substr(0, Filename.size()-1);
2329a6ac540bab63380a4a78d8fad87f23c50878685John Thompson
2335f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  ++NumDirLookups;
2345f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt =
235f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris Lattner    DirEntries.GetOrCreateValue(Filename);
2361eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2375f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // See if there is already an entry in the map.
2385f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  if (NamedDirEnt.getValue())
2393d2da3d765123e15290c38ba44f4434462bb88d5Ted Kremenek    return NamedDirEnt.getValue() == NON_EXISTENT_DIR
2405f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer              ? 0 : NamedDirEnt.getValue();
2411eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2425f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  ++NumDirCacheMisses;
2431eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2445f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // By default, initialize it to invalid.
2453d2da3d765123e15290c38ba44f4434462bb88d5Ted Kremenek  NamedDirEnt.setValue(NON_EXISTENT_DIR);
2461eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2475f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // Get the null-terminated directory name as stored as the key of the
2485f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // DirEntries map.
2495f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  const char *InterndDirName = NamedDirEnt.getKeyData();
2501eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2515f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // Check to see if the directory exists.
2525f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  struct stat StatBuf;
253389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis  if (stat_cached(InterndDirName, &StatBuf, FileSystemOpts) ||   // Error stat'ing.
2545f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      !S_ISDIR(StatBuf.st_mode))          // Not a directory?
2555f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    return 0;
2566bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
2575f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // It exists.  See if we have already opened a directory with the same inode.
2581eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  // This occurs when one dir is symlinked to another, for example.
2596bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  DirectoryEntry &UDE = UniqueDirs.getDirectory(InterndDirName, StatBuf);
2601eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2615f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  NamedDirEnt.setValue(&UDE);
2625f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  if (UDE.getName()) // Already have an entry with this inode, return it.
2635f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    return &UDE;
2641eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2655f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // Otherwise, we don't have this directory yet, add it.  We use the string
2665f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // key from the DirEntries map as the string.
2675f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  UDE.Name  = InterndDirName;
2685f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  return &UDE;
2695f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer}
2705f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
2713d2da3d765123e15290c38ba44f4434462bb88d5Ted Kremenek/// NON_EXISTENT_FILE - A special value distinct from null that is used to
2725f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// represent a filename that doesn't exist on the disk.
2733d2da3d765123e15290c38ba44f4434462bb88d5Ted Kremenek#define NON_EXISTENT_FILE reinterpret_cast<FileEntry*>((intptr_t)-1)
2745f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
2755f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// getFile - Lookup, cache, and verify the specified file.  This returns null
2765f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// if the file doesn't exist.
2771eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump///
278f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris Lattnerconst FileEntry *FileManager::getFile(llvm::StringRef Filename,
279389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis                                      const FileSystemOptions &FileSystemOpts) {
2805f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  ++NumFileLookups;
2811eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2825f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // See if there is already an entry in the map.
2835f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  llvm::StringMapEntry<FileEntry *> &NamedFileEnt =
284f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris Lattner    FileEntries.GetOrCreateValue(Filename);
2855f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
2865f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // See if there is already an entry in the map.
2875f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  if (NamedFileEnt.getValue())
2883d2da3d765123e15290c38ba44f4434462bb88d5Ted Kremenek    return NamedFileEnt.getValue() == NON_EXISTENT_FILE
2895f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer                 ? 0 : NamedFileEnt.getValue();
2901eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2915f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  ++NumFileCacheMisses;
2925f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
2935f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // By default, initialize it to invalid.
2943d2da3d765123e15290c38ba44f4434462bb88d5Ted Kremenek  NamedFileEnt.setValue(NON_EXISTENT_FILE);
2955f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
2961eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2975f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // Get the null-terminated file name as stored as the key of the
2985f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // FileEntries map.
2995f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  const char *InterndFileName = NamedFileEnt.getKeyData();
3001eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
301057e567f1b375190779e5341f42861896cdee442Douglas Gregor  const DirectoryEntry *DirInfo
302f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris Lattner    = getDirectoryFromFile(*this, Filename, FileSystemOpts);
303057e567f1b375190779e5341f42861896cdee442Douglas Gregor  if (DirInfo == 0)  // Directory doesn't exist, file can't exist.
304057e567f1b375190779e5341f42861896cdee442Douglas Gregor    return 0;
305057e567f1b375190779e5341f42861896cdee442Douglas Gregor
3065f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // FIXME: Use the directory info to prune this, before doing the stat syscall.
3075f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // FIXME: This will reduce the # syscalls.
3081eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
3095f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // Nope, there isn't.  Check to see if the file exists.
3105f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  struct stat StatBuf;
3116cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer  //llvm::errs() << "STATING: " << Filename;
312389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis  if (stat_cached(InterndFileName, &StatBuf, FileSystemOpts) ||   // Error stat'ing.
313fc7052d4a241ee6fc70afea7c1c9560147f0a49cTed Kremenek        S_ISDIR(StatBuf.st_mode)) {           // A directory?
3145f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    // If this file doesn't exist, we leave a null in FileEntries for this path.
3156cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer    //llvm::errs() << ": Not existing\n";
3165f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    return 0;
3175f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  }
3186cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer  //llvm::errs() << ": exists\n";
3191eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
320bca6d125c77c93c7fa41798c15348175a6bb1267Ted Kremenek  // It exists.  See if we have already opened a file with the same inode.
3215f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // This occurs when one dir is symlinked to another, for example.
3226bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  FileEntry &UFE = UniqueFiles.getFile(InterndFileName, StatBuf);
3231eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
3245f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  NamedFileEnt.setValue(&UFE);
3255f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  if (UFE.getName())  // Already have an entry with this inode, return it.
3265f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    return &UFE;
3275f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
3285f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // Otherwise, we don't have this directory yet, add it.
3295f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // FIXME: Change the name to be a char* that points back to the 'FileEntries'
3305f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // key.
3315f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  UFE.Name    = InterndFileName;
3325f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  UFE.Size    = StatBuf.st_size;
3335f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  UFE.ModTime = StatBuf.st_mtime;
3345f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  UFE.Dir     = DirInfo;
3355f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  UFE.UID     = NextFileUID++;
3365f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  return &UFE;
3375f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer}
3385f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
339057e567f1b375190779e5341f42861896cdee442Douglas Gregorconst FileEntry *
340ec1b1cc006cef19e0a95d0ea6fbfd37d0d615066Benjamin KramerFileManager::getVirtualFile(llvm::StringRef Filename, off_t Size,
341389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis                            time_t ModificationTime,
342389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis                            const FileSystemOptions &FileSystemOpts) {
343057e567f1b375190779e5341f42861896cdee442Douglas Gregor  ++NumFileLookups;
344057e567f1b375190779e5341f42861896cdee442Douglas Gregor
345057e567f1b375190779e5341f42861896cdee442Douglas Gregor  // See if there is already an entry in the map.
346057e567f1b375190779e5341f42861896cdee442Douglas Gregor  llvm::StringMapEntry<FileEntry *> &NamedFileEnt =
347f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris Lattner    FileEntries.GetOrCreateValue(Filename);
348057e567f1b375190779e5341f42861896cdee442Douglas Gregor
349057e567f1b375190779e5341f42861896cdee442Douglas Gregor  // See if there is already an entry in the map.
350057e567f1b375190779e5341f42861896cdee442Douglas Gregor  if (NamedFileEnt.getValue())
351057e567f1b375190779e5341f42861896cdee442Douglas Gregor    return NamedFileEnt.getValue() == NON_EXISTENT_FILE
352057e567f1b375190779e5341f42861896cdee442Douglas Gregor                 ? 0 : NamedFileEnt.getValue();
353057e567f1b375190779e5341f42861896cdee442Douglas Gregor
354057e567f1b375190779e5341f42861896cdee442Douglas Gregor  ++NumFileCacheMisses;
355057e567f1b375190779e5341f42861896cdee442Douglas Gregor
356057e567f1b375190779e5341f42861896cdee442Douglas Gregor  // By default, initialize it to invalid.
357057e567f1b375190779e5341f42861896cdee442Douglas Gregor  NamedFileEnt.setValue(NON_EXISTENT_FILE);
358057e567f1b375190779e5341f42861896cdee442Douglas Gregor
359057e567f1b375190779e5341f42861896cdee442Douglas Gregor  const DirectoryEntry *DirInfo
360f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris Lattner    = getDirectoryFromFile(*this, Filename, FileSystemOpts);
361057e567f1b375190779e5341f42861896cdee442Douglas Gregor  if (DirInfo == 0)  // Directory doesn't exist, file can't exist.
362057e567f1b375190779e5341f42861896cdee442Douglas Gregor    return 0;
363057e567f1b375190779e5341f42861896cdee442Douglas Gregor
364057e567f1b375190779e5341f42861896cdee442Douglas Gregor  FileEntry *UFE = new FileEntry();
365057e567f1b375190779e5341f42861896cdee442Douglas Gregor  VirtualFileEntries.push_back(UFE);
366057e567f1b375190779e5341f42861896cdee442Douglas Gregor  NamedFileEnt.setValue(UFE);
367057e567f1b375190779e5341f42861896cdee442Douglas Gregor
368057e567f1b375190779e5341f42861896cdee442Douglas Gregor  UFE->Name    = NamedFileEnt.getKeyData();
369057e567f1b375190779e5341f42861896cdee442Douglas Gregor  UFE->Size    = Size;
370057e567f1b375190779e5341f42861896cdee442Douglas Gregor  UFE->ModTime = ModificationTime;
371057e567f1b375190779e5341f42861896cdee442Douglas Gregor  UFE->Dir     = DirInfo;
372057e567f1b375190779e5341f42861896cdee442Douglas Gregor  UFE->UID     = NextFileUID++;
3733e15e0a7b4da6d906357b00b1bd2bba5ec3195edDouglas Gregor
3743e15e0a7b4da6d906357b00b1bd2bba5ec3195edDouglas Gregor  // If this virtual file resolves to a file, also map that file to the
3753e15e0a7b4da6d906357b00b1bd2bba5ec3195edDouglas Gregor  // newly-created file entry.
3763e15e0a7b4da6d906357b00b1bd2bba5ec3195edDouglas Gregor  const char *InterndFileName = NamedFileEnt.getKeyData();
3773e15e0a7b4da6d906357b00b1bd2bba5ec3195edDouglas Gregor  struct stat StatBuf;
378389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis  if (!stat_cached(InterndFileName, &StatBuf, FileSystemOpts) &&
3793e15e0a7b4da6d906357b00b1bd2bba5ec3195edDouglas Gregor      !S_ISDIR(StatBuf.st_mode)) {
3803e15e0a7b4da6d906357b00b1bd2bba5ec3195edDouglas Gregor    llvm::sys::Path FilePath(InterndFileName);
3813e15e0a7b4da6d906357b00b1bd2bba5ec3195edDouglas Gregor    FilePath.makeAbsolute();
3823e15e0a7b4da6d906357b00b1bd2bba5ec3195edDouglas Gregor    FileEntries[FilePath.str()] = UFE;
3833e15e0a7b4da6d906357b00b1bd2bba5ec3195edDouglas Gregor  }
3843e15e0a7b4da6d906357b00b1bd2bba5ec3195edDouglas Gregor
385057e567f1b375190779e5341f42861896cdee442Douglas Gregor  return UFE;
386057e567f1b375190779e5341f42861896cdee442Douglas Gregor}
387057e567f1b375190779e5341f42861896cdee442Douglas Gregor
388f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris Lattnerllvm::MemoryBuffer *FileManager::
389f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris LattnergetBufferForFile(const char *FilenameStart, const char *FilenameEnd,
390f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris Lattner                 const FileSystemOptions &FileSystemOpts,
391f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris Lattner                 std::string *ErrorStr,
392f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris Lattner                 int64_t FileSize,
393f69a1f319bd3c846c4a9ab84ea615e4e37dfd359Chris Lattner                 struct stat *FileInfo) {
394389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis  llvm::sys::Path FilePath(llvm::StringRef(FilenameStart,
395389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis                                           FilenameEnd-FilenameStart));
396389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis  FixupRelativePath(FilePath, FileSystemOpts);
397389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis
398389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis  return llvm::MemoryBuffer::getFile(FilePath.c_str(), ErrorStr,
399389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis                                     FileSize, FileInfo);
400389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis}
401389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis
402389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidisint FileManager::stat_cached(const char* path, struct stat* buf,
403389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis                             const FileSystemOptions &FileSystemOpts) {
404389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis  llvm::sys::Path FilePath(path);
405389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis  FixupRelativePath(FilePath, FileSystemOpts);
406389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis
407389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis  return StatCache.get() ? StatCache->stat(FilePath.c_str(), buf)
408389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis                         : stat(FilePath.c_str(), buf);
409389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis}
410389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis
411389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidisvoid FileManager::FixupRelativePath(llvm::sys::Path &path,
412389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis                                    const FileSystemOptions &FSOpts) {
413389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis  if (!FSOpts.WorkingDir.empty() && !path.isAbsolute()) {
414389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis    llvm::sys::Path NewPath(FSOpts.WorkingDir);
415389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis    NewPath.appendComponent(path.str());
416389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis    path = NewPath;
417389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis  }
418389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis}
419389db16c63eec6ecfa9b235155252d8da766e94eArgyrios Kyrtzidis
4205f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencervoid FileManager::PrintStats() const {
4216cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer  llvm::errs() << "\n*** File Manager Stats:\n";
4226cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer  llvm::errs() << UniqueFiles.size() << " files found, "
4236cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer               << UniqueDirs.size() << " dirs found.\n";
4246cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer  llvm::errs() << NumDirLookups << " dir lookups, "
4256cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer               << NumDirCacheMisses << " dir cache misses.\n";
4266cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer  llvm::errs() << NumFileLookups << " file lookups, "
4276cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer               << NumFileCacheMisses << " file cache misses.\n";
4281eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
4296cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer  //llvm::errs() << PagesMapped << BytesOfPagesMapped << FSLookups;
4305f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer}
4314fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor
4324fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregorint MemorizeStatCalls::stat(const char *path, struct stat *buf) {
43352e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor  int result = StatSysCallCache::stat(path, buf);
43452e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor
435475ddb4547ce35706ce1ff54b14bdcfdc51954c2Daniel Dunbar  // Do not cache failed stats, it is easy to construct common inconsistent
436475ddb4547ce35706ce1ff54b14bdcfdc51954c2Daniel Dunbar  // situations if we do, and they are not important for PCH performance (which
437475ddb4547ce35706ce1ff54b14bdcfdc51954c2Daniel Dunbar  // currently only needs the stats to construct the initial FileManager
438475ddb4547ce35706ce1ff54b14bdcfdc51954c2Daniel Dunbar  // entries).
439475ddb4547ce35706ce1ff54b14bdcfdc51954c2Daniel Dunbar  if (result != 0)
440475ddb4547ce35706ce1ff54b14bdcfdc51954c2Daniel Dunbar    return result;
441475ddb4547ce35706ce1ff54b14bdcfdc51954c2Daniel Dunbar
442475ddb4547ce35706ce1ff54b14bdcfdc51954c2Daniel Dunbar  // Cache file 'stat' results and directories with absolutely paths.
443475ddb4547ce35706ce1ff54b14bdcfdc51954c2Daniel Dunbar  if (!S_ISDIR(buf->st_mode) || llvm::sys::Path(path).isAbsolute())
4444fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor    StatCalls[path] = StatResult(result, *buf);
4451eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
4461eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  return result;
4474fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor}
448