FileManager.cpp revision 52e7108f51a4a9f4d6e84f33fb594d06e1d79560
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"
215f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer#include "llvm/ADT/SmallString.h"
22d57a7ef9252964bc6c8471451d7bd395b0520cb8Chris Lattner#include "llvm/Support/raw_ostream.h"
234fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor#include "llvm/System/Path.h"
246bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek#include "llvm/Config/config.h"
25458fb10ef5ba2d7b375c6c64095c1458af0a5be3Benjamin Kramer#include <map>
26458fb10ef5ba2d7b375c6c64095c1458af0a5be3Benjamin Kramer#include <set>
27458fb10ef5ba2d7b375c6c64095c1458af0a5be3Benjamin Kramer#include <string>
285f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencerusing namespace clang;
295f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
305f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// FIXME: Enhance libsystem to support inode and other fields.
315f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer#include <sys/stat.h>
325f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
33a8c11c6a7831df37f2f40b34072360b04f6d19a8Chris Lattner#if defined(_MSC_VER)
343102c83f6eac0cbbd698471173672c3e47a6914cChris Lattner#define S_ISDIR(s) (_S_IFDIR & s)
35a8c11c6a7831df37f2f40b34072360b04f6d19a8Chris Lattner#endif
365f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
373d2da3d765123e15290c38ba44f4434462bb88d5Ted Kremenek/// NON_EXISTENT_DIR - A special value distinct from null that is used to
385f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// represent a dir name that doesn't exist on the disk.
393d2da3d765123e15290c38ba44f4434462bb88d5Ted Kremenek#define NON_EXISTENT_DIR reinterpret_cast<DirectoryEntry*>((intptr_t)-1)
405f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
41cb8d58b82859d2c56b679b901de38f416e2b6f48Ted Kremenek//===----------------------------------------------------------------------===//
42cb8d58b82859d2c56b679b901de38f416e2b6f48Ted Kremenek// Windows.
43cb8d58b82859d2c56b679b901de38f416e2b6f48Ted Kremenek//===----------------------------------------------------------------------===//
44cb8d58b82859d2c56b679b901de38f416e2b6f48Ted Kremenek
456bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek#ifdef LLVM_ON_WIN32
466bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
476bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek#define IS_DIR_SEPARATOR_CHAR(x) ((x) == '/' || (x) == '\\')
486bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
496bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremeneknamespace {
501eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  static std::string GetFullPath(const char *relPath) {
516bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek    char *absPathStrPtr = _fullpath(NULL, relPath, 0);
526bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek    assert(absPathStrPtr && "_fullpath() returned NULL!");
536bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
546bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek    std::string absPath(absPathStrPtr);
556bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
566bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek    free(absPathStrPtr);
576bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek    return absPath;
586bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  }
596bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek}
606bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
616bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenekclass FileManager::UniqueDirContainer {
626bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  /// UniqueDirs - Cache from full path to existing directories/files.
636bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  ///
641eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  llvm::StringMap<DirectoryEntry> UniqueDirs;
656bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
666bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenekpublic:
676bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  DirectoryEntry &getDirectory(const char *Name, struct stat &StatBuf) {
686bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek    std::string FullPath(GetFullPath(Name));
696bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek    return UniqueDirs.GetOrCreateValue(
706bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek                              FullPath.c_str(),
716bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek                              FullPath.c_str() + FullPath.size()
726bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek                                                                ).getValue();
736bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  }
741eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
756bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  size_t size() { return UniqueDirs.size(); }
766bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek};
776bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
786bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenekclass FileManager::UniqueFileContainer {
796bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  /// UniqueFiles - Cache from full path to existing directories/files.
806bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  ///
8175368893339d89f6523c312b0a0eb23d438b6dffTed Kremenek  llvm::StringMap<FileEntry, llvm::BumpPtrAllocator> UniqueFiles;
826bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
836bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenekpublic:
846bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  FileEntry &getFile(const char *Name, struct stat &StatBuf) {
856bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek    std::string FullPath(GetFullPath(Name));
866bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek    return UniqueFiles.GetOrCreateValue(
876bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek                               FullPath.c_str(),
886bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek                               FullPath.c_str() + FullPath.size()
896bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek                                                                 ).getValue();
906bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  }
916bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
926bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  size_t size() { return UniqueFiles.size(); }
936bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek};
946bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
95cb8d58b82859d2c56b679b901de38f416e2b6f48Ted Kremenek//===----------------------------------------------------------------------===//
96cb8d58b82859d2c56b679b901de38f416e2b6f48Ted Kremenek// Unix-like Systems.
97cb8d58b82859d2c56b679b901de38f416e2b6f48Ted Kremenek//===----------------------------------------------------------------------===//
98cb8d58b82859d2c56b679b901de38f416e2b6f48Ted Kremenek
996bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek#else
1006bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
1016bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek#define IS_DIR_SEPARATOR_CHAR(x) ((x) == '/')
1026bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
1036bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenekclass FileManager::UniqueDirContainer {
1046bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  /// UniqueDirs - Cache from ID's to existing directories/files.
1056bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  ///
1061eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  std::map<std::pair<dev_t, ino_t>, DirectoryEntry> UniqueDirs;
1076bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
1086bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenekpublic:
1096bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  DirectoryEntry &getDirectory(const char *Name, struct stat &StatBuf) {
1106bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek    return UniqueDirs[std::make_pair(StatBuf.st_dev, StatBuf.st_ino)];
1116bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  }
1126bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
1136bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  size_t size() { return UniqueDirs.size(); }
1146bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek};
1156bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
1166bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenekclass FileManager::UniqueFileContainer {
1176bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  /// UniqueFiles - Cache from ID's to existing directories/files.
1186bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  ///
1196bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  std::set<FileEntry> UniqueFiles;
1206bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
1216bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenekpublic:
1226bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  FileEntry &getFile(const char *Name, struct stat &StatBuf) {
1236bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek    return
1246bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek      const_cast<FileEntry&>(
1256bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek                    *UniqueFiles.insert(FileEntry(StatBuf.st_dev,
12696438f319bb07d9a40564b5e01333f82c0c8a61eTed Kremenek                                                  StatBuf.st_ino,
12796438f319bb07d9a40564b5e01333f82c0c8a61eTed Kremenek                                                  StatBuf.st_mode)).first);
1286bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  }
1296bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
1306bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  size_t size() { return UniqueFiles.size(); }
1316bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek};
1326bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
1336bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek#endif
1346bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
135cb8d58b82859d2c56b679b901de38f416e2b6f48Ted Kremenek//===----------------------------------------------------------------------===//
136cb8d58b82859d2c56b679b901de38f416e2b6f48Ted Kremenek// Common logic.
137cb8d58b82859d2c56b679b901de38f416e2b6f48Ted Kremenek//===----------------------------------------------------------------------===//
1386bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
13996438f319bb07d9a40564b5e01333f82c0c8a61eTed KremenekFileManager::FileManager()
140fc7052d4a241ee6fc70afea7c1c9560147f0a49cTed Kremenek  : UniqueDirs(*new UniqueDirContainer),
141fc7052d4a241ee6fc70afea7c1c9560147f0a49cTed Kremenek    UniqueFiles(*new UniqueFileContainer),
14296438f319bb07d9a40564b5e01333f82c0c8a61eTed Kremenek    DirEntries(64), FileEntries(64), NextFileUID(0) {
1436bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  NumDirLookups = NumFileLookups = 0;
1446bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  NumDirCacheMisses = NumFileCacheMisses = 0;
1456bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek}
1466bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
1476bb816a3b895e9c983d89b22d510dca58a0eb75eTed KremenekFileManager::~FileManager() {
1486bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  delete &UniqueDirs;
1496bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  delete &UniqueFiles;
1506bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek}
1516bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
15252e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregorvoid FileManager::addStatCache(StatSysCallCache *statCache, bool AtBeginning) {
15352e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor  assert(statCache && "No stat cache provided?");
15452e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor  if (AtBeginning || StatCache.get() == 0) {
15552e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor    statCache->setNextStatCache(StatCache.take());
15652e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor    StatCache.reset(statCache);
15752e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor    return;
15852e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor  }
15952e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor
16052e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor  StatSysCallCache *LastCache = StatCache.get();
16152e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor  while (LastCache->getNextStatCache())
16252e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor    LastCache = LastCache->getNextStatCache();
16352e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor
16452e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor  LastCache->setNextStatCache(statCache);
16552e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor}
16652e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor
16752e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregorvoid FileManager::removeStatCache(StatSysCallCache *statCache) {
16852e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor  if (!statCache)
16952e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor    return;
17052e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor
17152e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor  if (StatCache.get() == statCache) {
17252e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor    // This is the first stat cache.
17352e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor    StatCache.reset(StatCache->takeNextStatCache());
17452e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor    return;
17552e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor  }
17652e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor
17752e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor  // Find the stat cache in the list.
17852e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor  StatSysCallCache *PrevCache = StatCache.get();
17952e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor  while (PrevCache && PrevCache->getNextStatCache() != statCache)
18052e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor    PrevCache = PrevCache->getNextStatCache();
18152e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor  if (PrevCache)
18252e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor    PrevCache->setNextStatCache(statCache->getNextStatCache());
18352e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor  else
18452e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor    assert(false && "Stat cache not found for removal");
18552e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor}
18652e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor
1875f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// getDirectory - Lookup, cache, and verify the specified directory.  This
1885f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// returns null if the directory doesn't exist.
1891eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump///
1905f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencerconst DirectoryEntry *FileManager::getDirectory(const char *NameStart,
1915f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer                                                const char *NameEnd) {
1925f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  ++NumDirLookups;
1935f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt =
1945f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    DirEntries.GetOrCreateValue(NameStart, NameEnd);
1951eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
1965f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // See if there is already an entry in the map.
1975f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  if (NamedDirEnt.getValue())
1983d2da3d765123e15290c38ba44f4434462bb88d5Ted Kremenek    return NamedDirEnt.getValue() == NON_EXISTENT_DIR
1995f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer              ? 0 : NamedDirEnt.getValue();
2001eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2015f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  ++NumDirCacheMisses;
2021eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2035f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // By default, initialize it to invalid.
2043d2da3d765123e15290c38ba44f4434462bb88d5Ted Kremenek  NamedDirEnt.setValue(NON_EXISTENT_DIR);
2051eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2065f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // Get the null-terminated directory name as stored as the key of the
2075f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // DirEntries map.
2085f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  const char *InterndDirName = NamedDirEnt.getKeyData();
2091eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2105f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // Check to see if the directory exists.
2115f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  struct stat StatBuf;
212fc7052d4a241ee6fc70afea7c1c9560147f0a49cTed Kremenek  if (stat_cached(InterndDirName, &StatBuf) ||   // Error stat'ing.
2135f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      !S_ISDIR(StatBuf.st_mode))          // Not a directory?
2145f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    return 0;
2156bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek
2165f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // It exists.  See if we have already opened a directory with the same inode.
2171eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  // This occurs when one dir is symlinked to another, for example.
2186bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  DirectoryEntry &UDE = UniqueDirs.getDirectory(InterndDirName, StatBuf);
2191eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2205f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  NamedDirEnt.setValue(&UDE);
2215f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  if (UDE.getName()) // Already have an entry with this inode, return it.
2225f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    return &UDE;
2231eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2245f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // Otherwise, we don't have this directory yet, add it.  We use the string
2255f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // key from the DirEntries map as the string.
2265f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  UDE.Name  = InterndDirName;
2275f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  return &UDE;
2285f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer}
2295f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
2303d2da3d765123e15290c38ba44f4434462bb88d5Ted Kremenek/// NON_EXISTENT_FILE - A special value distinct from null that is used to
2315f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// represent a filename that doesn't exist on the disk.
2323d2da3d765123e15290c38ba44f4434462bb88d5Ted Kremenek#define NON_EXISTENT_FILE reinterpret_cast<FileEntry*>((intptr_t)-1)
2335f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
2345f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// getFile - Lookup, cache, and verify the specified file.  This returns null
2355f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// if the file doesn't exist.
2361eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump///
2375f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencerconst FileEntry *FileManager::getFile(const char *NameStart,
2385f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer                                      const char *NameEnd) {
2395f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  ++NumFileLookups;
2401eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2415f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // See if there is already an entry in the map.
2425f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  llvm::StringMapEntry<FileEntry *> &NamedFileEnt =
2435f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    FileEntries.GetOrCreateValue(NameStart, NameEnd);
2445f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
2455f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // See if there is already an entry in the map.
2465f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  if (NamedFileEnt.getValue())
2473d2da3d765123e15290c38ba44f4434462bb88d5Ted Kremenek    return NamedFileEnt.getValue() == NON_EXISTENT_FILE
2485f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer                 ? 0 : NamedFileEnt.getValue();
2491eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2505f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  ++NumFileCacheMisses;
2515f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
2525f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // By default, initialize it to invalid.
2533d2da3d765123e15290c38ba44f4434462bb88d5Ted Kremenek  NamedFileEnt.setValue(NON_EXISTENT_FILE);
2545f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
2555f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // Figure out what directory it is in.   If the string contains a / in it,
2565f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // strip off everything after it.
2575f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // FIXME: this logic should be in sys::Path.
2585f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  const char *SlashPos = NameEnd-1;
2596bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  while (SlashPos >= NameStart && !IS_DIR_SEPARATOR_CHAR(SlashPos[0]))
2605f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    --SlashPos;
26146730b261c46765c51a9aa83c2571a2a8705482aChris Lattner  // Ignore duplicate //'s.
26246730b261c46765c51a9aa83c2571a2a8705482aChris Lattner  while (SlashPos > NameStart && IS_DIR_SEPARATOR_CHAR(SlashPos[-1]))
26346730b261c46765c51a9aa83c2571a2a8705482aChris Lattner    --SlashPos;
2641eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2655f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  const DirectoryEntry *DirInfo;
2665f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  if (SlashPos < NameStart) {
2675f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    // Use the current directory if file has no path component.
2685f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    const char *Name = ".";
2695f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    DirInfo = getDirectory(Name, Name+1);
2705f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  } else if (SlashPos == NameEnd-1)
2715f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    return 0;       // If filename ends with a /, it's a directory.
2725f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  else
2735f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    DirInfo = getDirectory(NameStart, SlashPos);
2741eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2755f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  if (DirInfo == 0)  // Directory doesn't exist, file can't exist.
2765f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    return 0;
2771eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2785f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // Get the null-terminated file name as stored as the key of the
2795f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // FileEntries map.
2805f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  const char *InterndFileName = NamedFileEnt.getKeyData();
2811eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2825f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // FIXME: Use the directory info to prune this, before doing the stat syscall.
2835f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // FIXME: This will reduce the # syscalls.
2841eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
2855f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // Nope, there isn't.  Check to see if the file exists.
2865f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  struct stat StatBuf;
2876cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer  //llvm::errs() << "STATING: " << Filename;
288fc7052d4a241ee6fc70afea7c1c9560147f0a49cTed Kremenek  if (stat_cached(InterndFileName, &StatBuf) ||   // Error stat'ing.
289fc7052d4a241ee6fc70afea7c1c9560147f0a49cTed Kremenek        S_ISDIR(StatBuf.st_mode)) {           // A directory?
2905f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    // If this file doesn't exist, we leave a null in FileEntries for this path.
2916cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer    //llvm::errs() << ": Not existing\n";
2925f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    return 0;
2935f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  }
2946cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer  //llvm::errs() << ": exists\n";
2951eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
296bca6d125c77c93c7fa41798c15348175a6bb1267Ted Kremenek  // It exists.  See if we have already opened a file with the same inode.
2975f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // This occurs when one dir is symlinked to another, for example.
2986bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek  FileEntry &UFE = UniqueFiles.getFile(InterndFileName, StatBuf);
2991eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
3005f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  NamedFileEnt.setValue(&UFE);
3015f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  if (UFE.getName())  // Already have an entry with this inode, return it.
3025f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    return &UFE;
3035f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
3045f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // Otherwise, we don't have this directory yet, add it.
3055f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // FIXME: Change the name to be a char* that points back to the 'FileEntries'
3065f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // key.
3075f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  UFE.Name    = InterndFileName;
3085f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  UFE.Size    = StatBuf.st_size;
3095f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  UFE.ModTime = StatBuf.st_mtime;
3105f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  UFE.Dir     = DirInfo;
3115f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  UFE.UID     = NextFileUID++;
3125f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  return &UFE;
3135f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer}
3145f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
3155f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencervoid FileManager::PrintStats() const {
3166cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer  llvm::errs() << "\n*** File Manager Stats:\n";
3176cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer  llvm::errs() << UniqueFiles.size() << " files found, "
3186cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer               << UniqueDirs.size() << " dirs found.\n";
3196cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer  llvm::errs() << NumDirLookups << " dir lookups, "
3206cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer               << NumDirCacheMisses << " dir cache misses.\n";
3216cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer  llvm::errs() << NumFileLookups << " file lookups, "
3226cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer               << NumFileCacheMisses << " file cache misses.\n";
3231eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
3246cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer  //llvm::errs() << PagesMapped << BytesOfPagesMapped << FSLookups;
3255f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer}
3264fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor
3274fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregorint MemorizeStatCalls::stat(const char *path, struct stat *buf) {
32852e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor  int result = StatSysCallCache::stat(path, buf);
32952e7108f51a4a9f4d6e84f33fb594d06e1d79560Douglas Gregor
3301eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  if (result != 0) {
3314fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor    // Cache failed 'stat' results.
3324fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor    struct stat empty;
333f1affe6129442b230d3d09b1938e07a7b341a102Chris Lattner    memset(&empty, 0, sizeof(empty));
3344fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor    StatCalls[path] = StatResult(result, empty);
3354fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor  }
3364fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor  else if (!S_ISDIR(buf->st_mode) || llvm::sys::Path(path).isAbsolute()) {
3374fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor    // Cache file 'stat' results and directories with absolutely
3384fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor    // paths.
3394fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor    StatCalls[path] = StatResult(result, *buf);
3404fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor  }
3411eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump
3421eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump  return result;
3434fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor}
344