FileManager.cpp revision 8ef6c8cb6c5627240e2339fd7062c9873f821d7e
14b562cf889bc59e1914dd2c5d9fbd7e7bfa1ad77Argyrios Kyrtzidis//===--- FileManager.cpp - File System Probing and Caching ----------------===//
24b562cf889bc59e1914dd2c5d9fbd7e7bfa1ad77Argyrios Kyrtzidis//
34b562cf889bc59e1914dd2c5d9fbd7e7bfa1ad77Argyrios Kyrtzidis//                     The LLVM Compiler Infrastructure
44b562cf889bc59e1914dd2c5d9fbd7e7bfa1ad77Argyrios Kyrtzidis//
54b562cf889bc59e1914dd2c5d9fbd7e7bfa1ad77Argyrios Kyrtzidis// This file is distributed under the University of Illinois Open Source
64b562cf889bc59e1914dd2c5d9fbd7e7bfa1ad77Argyrios Kyrtzidis// License. See LICENSE.TXT for details.
74b562cf889bc59e1914dd2c5d9fbd7e7bfa1ad77Argyrios Kyrtzidis//
84b562cf889bc59e1914dd2c5d9fbd7e7bfa1ad77Argyrios Kyrtzidis//===----------------------------------------------------------------------===//
94b562cf889bc59e1914dd2c5d9fbd7e7bfa1ad77Argyrios Kyrtzidis//
104b562cf889bc59e1914dd2c5d9fbd7e7bfa1ad77Argyrios Kyrtzidis//  This file implements the FileManager interface.
114b562cf889bc59e1914dd2c5d9fbd7e7bfa1ad77Argyrios Kyrtzidis//
124b562cf889bc59e1914dd2c5d9fbd7e7bfa1ad77Argyrios Kyrtzidis//===----------------------------------------------------------------------===//
134b562cf889bc59e1914dd2c5d9fbd7e7bfa1ad77Argyrios Kyrtzidis//
140853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidis// TODO: This should index all interesting directories with dirent calls.
150853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidis//  getdirentries ?
160853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidis//  opendir/readdir_r/closedir ?
174ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor//
1831b87d8006d4863dd9b17e515ac720941efc38e3Daniel Dunbar//===----------------------------------------------------------------------===//
190853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidis
2036c4464ba6cfc2a63dc67c493ef2f5ab2aea09ccSteve Naroff#include "clang/Basic/FileManager.h"
21f96b524306ccfa623235d375deee79637bd38f29Steve Naroff#include "clang/Basic/FileSystemStatCache.h"
22a88084b78fd4ca5d3d858c14b02414f8cc399f02Douglas Gregor#include "llvm/ADT/SmallString.h"
23313e26c4e81f0e467490a530548450f4c824a6c4Douglas Gregor#include "llvm/ADT/StringExtras.h"
240853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidis#include "llvm/Support/FileSystem.h"
25f772d1e2a5688572d07f42896a50ac57a4a41fe8Daniel Dunbar#include "llvm/Support/MemoryBuffer.h"
26f772d1e2a5688572d07f42896a50ac57a4a41fe8Daniel Dunbar#include "llvm/Support/raw_ostream.h"
274db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor#include "llvm/Support/Path.h"
284db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor#include "llvm/Support/system_error.h"
294db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor#include "llvm/Config/config.h"
304db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor#include <map>
314db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor#include <set>
320853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidis#include <string>
330853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidis
34521bf9c529e653ab28896d027352d3e16e2672d5Daniel Dunbar// FIXME: This is terrible, we need this for ::close.
35521bf9c529e653ab28896d027352d3e16e2672d5Daniel Dunbar#if !defined(_MSC_VER) && !defined(__MINGW32__)
36521bf9c529e653ab28896d027352d3e16e2672d5Daniel Dunbar#include <unistd.h>
37521bf9c529e653ab28896d027352d3e16e2672d5Daniel Dunbar#include <sys/uio.h>
38521bf9c529e653ab28896d027352d3e16e2672d5Daniel Dunbar#else
39521bf9c529e653ab28896d027352d3e16e2672d5Daniel Dunbar#include <io.h>
40521bf9c529e653ab28896d027352d3e16e2672d5Daniel Dunbar#endif
41521bf9c529e653ab28896d027352d3e16e2672d5Daniel Dunbarusing namespace clang;
42521bf9c529e653ab28896d027352d3e16e2672d5Daniel Dunbar
43521bf9c529e653ab28896d027352d3e16e2672d5Daniel Dunbar// FIXME: Enhance libsystem to support inode and other fields.
440853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidis#include <sys/stat.h>
45f96b524306ccfa623235d375deee79637bd38f29Steve Naroff
46f96b524306ccfa623235d375deee79637bd38f29Steve Naroff/// NON_EXISTENT_DIR - A special value distinct from null that is used to
470853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidis/// represent a dir name that doesn't exist on the disk.
480853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidis#define NON_EXISTENT_DIR reinterpret_cast<DirectoryEntry*>((intptr_t)-1)
490853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidis
5036c4464ba6cfc2a63dc67c493ef2f5ab2aea09ccSteve Naroff/// NON_EXISTENT_FILE - A special value distinct from null that is used to
5136c4464ba6cfc2a63dc67c493ef2f5ab2aea09ccSteve Naroff/// represent a filename that doesn't exist on the disk.
5231b87d8006d4863dd9b17e515ac720941efc38e3Daniel Dunbar#define NON_EXISTENT_FILE reinterpret_cast<FileEntry*>((intptr_t)-1)
530853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidis
540853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidis
550853a02c3b04d96a3c432b883e403175c954cd81Argyrios KyrtzidisFileEntry::~FileEntry() {
560853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidis  // If this FileEntry owns an open file descriptor that never got used, close
574ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor  // it.
584ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor  if (FD != -1) ::close(FD);
59807b06157a1a5c050520fc194d32f16d22d423a8Daniel Dunbar}
60807b06157a1a5c050520fc194d32f16d22d423a8Daniel Dunbar
61807b06157a1a5c050520fc194d32f16d22d423a8Daniel Dunbar//===----------------------------------------------------------------------===//
62807b06157a1a5c050520fc194d32f16d22d423a8Daniel Dunbar// Windows.
637d1d49d2971b20a97b3c2a301470b9eaaa130137Douglas Gregor//===----------------------------------------------------------------------===//
647d1d49d2971b20a97b3c2a301470b9eaaa130137Douglas Gregor
657d1d49d2971b20a97b3c2a301470b9eaaa130137Douglas Gregor#ifdef LLVM_ON_WIN32
667d1d49d2971b20a97b3c2a301470b9eaaa130137Douglas Gregor
67c7822dbf3c01a2a5f837cff82ba7889ea755dacaDaniel Dunbar#define IS_DIR_SEPARATOR_CHAR(x) ((x) == '/' || (x) == '\\')
68f772d1e2a5688572d07f42896a50ac57a4a41fe8Daniel Dunbar
69c7822dbf3c01a2a5f837cff82ba7889ea755dacaDaniel Dunbarnamespace {
70c7822dbf3c01a2a5f837cff82ba7889ea755dacaDaniel Dunbar  static std::string GetFullPath(const char *relPath) {
71f772d1e2a5688572d07f42896a50ac57a4a41fe8Daniel Dunbar    char *absPathStrPtr = _fullpath(NULL, relPath, 0);
72f772d1e2a5688572d07f42896a50ac57a4a41fe8Daniel Dunbar    assert(absPathStrPtr && "_fullpath() returned NULL!");
73f772d1e2a5688572d07f42896a50ac57a4a41fe8Daniel Dunbar
74f772d1e2a5688572d07f42896a50ac57a4a41fe8Daniel Dunbar    std::string absPath(absPathStrPtr);
75f772d1e2a5688572d07f42896a50ac57a4a41fe8Daniel Dunbar
76f772d1e2a5688572d07f42896a50ac57a4a41fe8Daniel Dunbar    free(absPathStrPtr);
77f772d1e2a5688572d07f42896a50ac57a4a41fe8Daniel Dunbar    return absPath;
78f772d1e2a5688572d07f42896a50ac57a4a41fe8Daniel Dunbar  }
79f772d1e2a5688572d07f42896a50ac57a4a41fe8Daniel Dunbar}
8068d40e2d16b9fadba386853d6bbb60089291fdc5Daniel Dunbar
8168d40e2d16b9fadba386853d6bbb60089291fdc5Daniel Dunbarclass FileManager::UniqueDirContainer {
8268d40e2d16b9fadba386853d6bbb60089291fdc5Daniel Dunbar  /// UniqueDirs - Cache from full path to existing directories/files.
83f96b524306ccfa623235d375deee79637bd38f29Steve Naroff  ///
84f96b524306ccfa623235d375deee79637bd38f29Steve Naroff  llvm::StringMap<DirectoryEntry> UniqueDirs;
85f772d1e2a5688572d07f42896a50ac57a4a41fe8Daniel Dunbar
86a88084b78fd4ca5d3d858c14b02414f8cc399f02Douglas Gregorpublic:
87a88084b78fd4ca5d3d858c14b02414f8cc399f02Douglas Gregor  DirectoryEntry &getDirectory(const char *Name, struct stat &StatBuf) {
88a88084b78fd4ca5d3d858c14b02414f8cc399f02Douglas Gregor    std::string FullPath(GetFullPath(Name));
89a88084b78fd4ca5d3d858c14b02414f8cc399f02Douglas Gregor    return UniqueDirs.GetOrCreateValue(FullPath).getValue();
90313e26c4e81f0e467490a530548450f4c824a6c4Douglas Gregor  }
91313e26c4e81f0e467490a530548450f4c824a6c4Douglas Gregor
92313e26c4e81f0e467490a530548450f4c824a6c4Douglas Gregor  size_t size() const { return UniqueDirs.size(); }
93bdf6062bc10aa3b73b16402b440b8073310acd06Douglas Gregor};
94bdf6062bc10aa3b73b16402b440b8073310acd06Douglas Gregor
95bdf6062bc10aa3b73b16402b440b8073310acd06Douglas Gregorclass FileManager::UniqueFileContainer {
96bdf6062bc10aa3b73b16402b440b8073310acd06Douglas Gregor  /// UniqueFiles - Cache from full path to existing directories/files.
97bdf6062bc10aa3b73b16402b440b8073310acd06Douglas Gregor  ///
98bdf6062bc10aa3b73b16402b440b8073310acd06Douglas Gregor  llvm::StringMap<FileEntry, llvm::BumpPtrAllocator> UniqueFiles;
99bdf6062bc10aa3b73b16402b440b8073310acd06Douglas Gregor
100bdf6062bc10aa3b73b16402b440b8073310acd06Douglas Gregorpublic:
101bdf6062bc10aa3b73b16402b440b8073310acd06Douglas Gregor  FileEntry &getFile(const char *Name, struct stat &StatBuf) {
102bdf6062bc10aa3b73b16402b440b8073310acd06Douglas Gregor    std::string FullPath(GetFullPath(Name));
103313e26c4e81f0e467490a530548450f4c824a6c4Douglas Gregor
10431b87d8006d4863dd9b17e515ac720941efc38e3Daniel Dunbar    // LowercaseString because Windows filesystem is case insensitive.
10531b87d8006d4863dd9b17e515ac720941efc38e3Daniel Dunbar    FullPath = llvm::LowercaseString(FullPath);
106bdf6062bc10aa3b73b16402b440b8073310acd06Douglas Gregor    return UniqueFiles.GetOrCreateValue(FullPath).getValue();
1070853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidis  }
108bdf6062bc10aa3b73b16402b440b8073310acd06Douglas Gregor
109bdf6062bc10aa3b73b16402b440b8073310acd06Douglas Gregor  size_t size() const { return UniqueFiles.size(); }
110bdf6062bc10aa3b73b16402b440b8073310acd06Douglas Gregor};
111bdf6062bc10aa3b73b16402b440b8073310acd06Douglas Gregor
112bdf6062bc10aa3b73b16402b440b8073310acd06Douglas Gregor//===----------------------------------------------------------------------===//
113bdf6062bc10aa3b73b16402b440b8073310acd06Douglas Gregor// Unix-like Systems.
114bdf6062bc10aa3b73b16402b440b8073310acd06Douglas Gregor//===----------------------------------------------------------------------===//
115bdf6062bc10aa3b73b16402b440b8073310acd06Douglas Gregor
116bdf6062bc10aa3b73b16402b440b8073310acd06Douglas Gregor#else
117bdf6062bc10aa3b73b16402b440b8073310acd06Douglas Gregor
118bdf6062bc10aa3b73b16402b440b8073310acd06Douglas Gregor#define IS_DIR_SEPARATOR_CHAR(x) ((x) == '/')
119bdf6062bc10aa3b73b16402b440b8073310acd06Douglas Gregor
120bdf6062bc10aa3b73b16402b440b8073310acd06Douglas Gregorclass FileManager::UniqueDirContainer {
121bdf6062bc10aa3b73b16402b440b8073310acd06Douglas Gregor  /// UniqueDirs - Cache from ID's to existing directories/files.
122bdf6062bc10aa3b73b16402b440b8073310acd06Douglas Gregor  std::map<std::pair<dev_t, ino_t>, DirectoryEntry> UniqueDirs;
123bdf6062bc10aa3b73b16402b440b8073310acd06Douglas Gregor
124bdf6062bc10aa3b73b16402b440b8073310acd06Douglas Gregorpublic:
125bdf6062bc10aa3b73b16402b440b8073310acd06Douglas Gregor  DirectoryEntry &getDirectory(const char *Name, struct stat &StatBuf) {
126f715ca12bfc9fddfde75f98a197424434428b821Douglas Gregor    return UniqueDirs[std::make_pair(StatBuf.st_dev, StatBuf.st_ino)];
1270853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidis  }
1280853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidis
129c7822dbf3c01a2a5f837cff82ba7889ea755dacaDaniel Dunbar  size_t size() const { return UniqueDirs.size(); }
130c7822dbf3c01a2a5f837cff82ba7889ea755dacaDaniel Dunbar};
13131b87d8006d4863dd9b17e515ac720941efc38e3Daniel Dunbar
13231b87d8006d4863dd9b17e515ac720941efc38e3Daniel Dunbarclass FileManager::UniqueFileContainer {
1330853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidis  /// UniqueFiles - Cache from ID's to existing directories/files.
1340853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidis  std::set<FileEntry> UniqueFiles;
1350853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidis
1361eb4433ac451dc16f4133a88af2d002ac26c58efMike Stumppublic:
1370853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidis  FileEntry &getFile(const char *Name, struct stat &StatBuf) {
1380853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidis    return
1390853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidis      const_cast<FileEntry&>(
1404ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor                    *UniqueFiles.insert(FileEntry(StatBuf.st_dev,
1414ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor                                                  StatBuf.st_ino,
1424ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor                                                  StatBuf.st_mode)).first);
1434ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor  }
1444ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor
1454ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor  size_t size() const { return UniqueFiles.size(); }
14636c4464ba6cfc2a63dc67c493ef2f5ab2aea09ccSteve Naroff};
14736c4464ba6cfc2a63dc67c493ef2f5ab2aea09ccSteve Naroff
148f772d1e2a5688572d07f42896a50ac57a4a41fe8Daniel Dunbar#endif
14977accc11f04ed4ff9afd4e27d430144d4714be56Steve Naroff
150e19944c93961b7618f4f3f3185f698f46369ea54Steve Naroff//===----------------------------------------------------------------------===//
151b85bca2676b433ae555db09de4dd2823ff13b856Zhongxing Xu// Common logic.
152313e26c4e81f0e467490a530548450f4c824a6c4Douglas Gregor//===----------------------------------------------------------------------===//
153313e26c4e81f0e467490a530548450f4c824a6c4Douglas Gregor
154313e26c4e81f0e467490a530548450f4c824a6c4Douglas GregorFileManager::FileManager(const FileSystemOptions &FSO)
155313e26c4e81f0e467490a530548450f4c824a6c4Douglas Gregor  : FileSystemOpts(FSO),
156313e26c4e81f0e467490a530548450f4c824a6c4Douglas Gregor    UniqueDirs(*new UniqueDirContainer()),
157313e26c4e81f0e467490a530548450f4c824a6c4Douglas Gregor    UniqueFiles(*new UniqueFileContainer()),
158313e26c4e81f0e467490a530548450f4c824a6c4Douglas Gregor    DirEntries(64), FileEntries(64), NextFileUID(0) {
1597d1d49d2971b20a97b3c2a301470b9eaaa130137Douglas Gregor  NumDirLookups = NumFileLookups = 0;
160f772d1e2a5688572d07f42896a50ac57a4a41fe8Daniel Dunbar  NumDirCacheMisses = NumFileCacheMisses = 0;
161f96b524306ccfa623235d375deee79637bd38f29Steve Naroff}
162f96b524306ccfa623235d375deee79637bd38f29Steve Naroff
163f772d1e2a5688572d07f42896a50ac57a4a41fe8Daniel DunbarFileManager::~FileManager() {
164f772d1e2a5688572d07f42896a50ac57a4a41fe8Daniel Dunbar  delete &UniqueDirs;
165f772d1e2a5688572d07f42896a50ac57a4a41fe8Daniel Dunbar  delete &UniqueFiles;
166f772d1e2a5688572d07f42896a50ac57a4a41fe8Daniel Dunbar  for (unsigned i = 0, e = VirtualFileEntries.size(); i != e; ++i)
167f772d1e2a5688572d07f42896a50ac57a4a41fe8Daniel Dunbar    delete VirtualFileEntries[i];
168f772d1e2a5688572d07f42896a50ac57a4a41fe8Daniel Dunbar}
169f772d1e2a5688572d07f42896a50ac57a4a41fe8Daniel Dunbar
170f772d1e2a5688572d07f42896a50ac57a4a41fe8Daniel Dunbarvoid FileManager::addStatCache(FileSystemStatCache *statCache,
171f772d1e2a5688572d07f42896a50ac57a4a41fe8Daniel Dunbar                               bool AtBeginning) {
172f772d1e2a5688572d07f42896a50ac57a4a41fe8Daniel Dunbar  assert(statCache && "No stat cache provided?");
173a88084b78fd4ca5d3d858c14b02414f8cc399f02Douglas Gregor  if (AtBeginning || StatCache.get() == 0) {
174a88084b78fd4ca5d3d858c14b02414f8cc399f02Douglas Gregor    statCache->setNextStatCache(StatCache.take());
175a88084b78fd4ca5d3d858c14b02414f8cc399f02Douglas Gregor    StatCache.reset(statCache);
176a88084b78fd4ca5d3d858c14b02414f8cc399f02Douglas Gregor    return;
177a88084b78fd4ca5d3d858c14b02414f8cc399f02Douglas Gregor  }
178a88084b78fd4ca5d3d858c14b02414f8cc399f02Douglas Gregor
179a88084b78fd4ca5d3d858c14b02414f8cc399f02Douglas Gregor  FileSystemStatCache *LastCache = StatCache.get();
180a88084b78fd4ca5d3d858c14b02414f8cc399f02Douglas Gregor  while (LastCache->getNextStatCache())
181a88084b78fd4ca5d3d858c14b02414f8cc399f02Douglas Gregor    LastCache = LastCache->getNextStatCache();
1824db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor
1834db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  LastCache->setNextStatCache(statCache);
1844db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor}
1854db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor
1860853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidisvoid FileManager::removeStatCache(FileSystemStatCache *statCache) {
1870853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidis  if (!statCache)
18831b87d8006d4863dd9b17e515ac720941efc38e3Daniel Dunbar    return;
1890853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidis
1905262fda30b876c8aae95f2eb92e349418d6b14bbDaniel Dunbar  if (StatCache.get() == statCache) {
1915262fda30b876c8aae95f2eb92e349418d6b14bbDaniel Dunbar    // This is the first stat cache.
19231b87d8006d4863dd9b17e515ac720941efc38e3Daniel Dunbar    StatCache.reset(StatCache->takeNextStatCache());
19331b87d8006d4863dd9b17e515ac720941efc38e3Daniel Dunbar    return;
1940853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidis  }
1955262fda30b876c8aae95f2eb92e349418d6b14bbDaniel Dunbar
1965cf48766d626ff6b223acc9d4b7e415ca8480836Ted Kremenek  // Find the stat cache in the list.
1974db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  FileSystemStatCache *PrevCache = StatCache.get();
198a88084b78fd4ca5d3d858c14b02414f8cc399f02Douglas Gregor  while (PrevCache && PrevCache->getNextStatCache() != statCache)
199a88084b78fd4ca5d3d858c14b02414f8cc399f02Douglas Gregor    PrevCache = PrevCache->getNextStatCache();
200521bf9c529e653ab28896d027352d3e16e2672d5Daniel Dunbar
201521bf9c529e653ab28896d027352d3e16e2672d5Daniel Dunbar  assert(PrevCache && "Stat cache not found for removal");
202521bf9c529e653ab28896d027352d3e16e2672d5Daniel Dunbar  PrevCache->setNextStatCache(statCache->getNextStatCache());
203521bf9c529e653ab28896d027352d3e16e2672d5Daniel Dunbar}
204521bf9c529e653ab28896d027352d3e16e2672d5Daniel Dunbar
205f7acc37450d59ef751df73acb91de73850cc6517Daniel Dunbar/// \brief Retrieve the directory that the given file name resides in.
206521bf9c529e653ab28896d027352d3e16e2672d5Daniel Dunbarstatic const DirectoryEntry *getDirectoryFromFile(FileManager &FileMgr,
2075262fda30b876c8aae95f2eb92e349418d6b14bbDaniel Dunbar                                                  llvm::StringRef Filename) {
2085262fda30b876c8aae95f2eb92e349418d6b14bbDaniel Dunbar  // Figure out what directory it is in.   If the string contains a / in it,
209521bf9c529e653ab28896d027352d3e16e2672d5Daniel Dunbar  // strip off everything after it.
210521bf9c529e653ab28896d027352d3e16e2672d5Daniel Dunbar  // FIXME: this logic should be in sys::Path.
211521bf9c529e653ab28896d027352d3e16e2672d5Daniel Dunbar  size_t SlashPos = Filename.size();
212f7acc37450d59ef751df73acb91de73850cc6517Daniel Dunbar  while (SlashPos != 0 && !IS_DIR_SEPARATOR_CHAR(Filename[SlashPos-1]))
213521bf9c529e653ab28896d027352d3e16e2672d5Daniel Dunbar    --SlashPos;
214a88084b78fd4ca5d3d858c14b02414f8cc399f02Douglas Gregor
2154ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor  // Use the current directory if file has no path component.
2164ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor  if (SlashPos == 0)
217521bf9c529e653ab28896d027352d3e16e2672d5Daniel Dunbar    return FileMgr.getDirectory(".");
2187b55668db7618334cc40011d3c1e128524d89462Daniel Dunbar
2197b55668db7618334cc40011d3c1e128524d89462Daniel Dunbar  if (SlashPos == Filename.size()-1)
2207b55668db7618334cc40011d3c1e128524d89462Daniel Dunbar    return 0;       // If filename ends with a /, it's a directory.
2217b55668db7618334cc40011d3c1e128524d89462Daniel Dunbar
2227b55668db7618334cc40011d3c1e128524d89462Daniel Dunbar  // Ignore repeated //'s.
2237b55668db7618334cc40011d3c1e128524d89462Daniel Dunbar  while (SlashPos != 0 && IS_DIR_SEPARATOR_CHAR(Filename[SlashPos-1]))
2247b55668db7618334cc40011d3c1e128524d89462Daniel Dunbar    --SlashPos;
2255262fda30b876c8aae95f2eb92e349418d6b14bbDaniel Dunbar
2265262fda30b876c8aae95f2eb92e349418d6b14bbDaniel Dunbar  return FileMgr.getDirectory(Filename.substr(0, SlashPos));
2277b55668db7618334cc40011d3c1e128524d89462Daniel Dunbar}
228869824e87940f97b87064db2df2861e82e08a8c6Daniel Dunbar
2297b55668db7618334cc40011d3c1e128524d89462Daniel Dunbar/// getDirectory - Lookup, cache, and verify the specified directory.  This
2307b55668db7618334cc40011d3c1e128524d89462Daniel Dunbar/// returns null if the directory doesn't exist.
2317b55668db7618334cc40011d3c1e128524d89462Daniel Dunbar///
2327b55668db7618334cc40011d3c1e128524d89462Daniel Dunbarconst DirectoryEntry *FileManager::getDirectory(llvm::StringRef Filename) {
2337b55668db7618334cc40011d3c1e128524d89462Daniel Dunbar  // stat doesn't like trailing separators (at least on Windows).
2347b55668db7618334cc40011d3c1e128524d89462Daniel Dunbar  if (Filename.size() > 1 && IS_DIR_SEPARATOR_CHAR(Filename.back()))
235869824e87940f97b87064db2df2861e82e08a8c6Daniel Dunbar    Filename = Filename.substr(0, Filename.size()-1);
2367b55668db7618334cc40011d3c1e128524d89462Daniel Dunbar
2374db64a461cb3442934afe43c83ed3f17f7c11c1dDouglas Gregor  ++NumDirLookups;
238a88084b78fd4ca5d3d858c14b02414f8cc399f02Douglas Gregor  llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt =
2394ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor    DirEntries.GetOrCreateValue(Filename);
2404ae8f298b1ea51b4c2234f9148e2e4349c9bdd23Douglas Gregor
2410853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidis  // See if there is already an entry in the map.
2420853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidis  if (NamedDirEnt.getValue())
2430853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidis    return NamedDirEnt.getValue() == NON_EXISTENT_DIR
2440853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidis              ? 0 : NamedDirEnt.getValue();
2450853a02c3b04d96a3c432b883e403175c954cd81Argyrios Kyrtzidis
246  ++NumDirCacheMisses;
247
248  // By default, initialize it to invalid.
249  NamedDirEnt.setValue(NON_EXISTENT_DIR);
250
251  // Get the null-terminated directory name as stored as the key of the
252  // DirEntries map.
253  const char *InterndDirName = NamedDirEnt.getKeyData();
254
255  // Check to see if the directory exists.
256  struct stat StatBuf;
257  if (getStatValue(InterndDirName, StatBuf, 0/*directory lookup*/))
258    return 0;
259
260  // It exists.  See if we have already opened a directory with the same inode.
261  // This occurs when one dir is symlinked to another, for example.
262  DirectoryEntry &UDE = UniqueDirs.getDirectory(InterndDirName, StatBuf);
263
264  NamedDirEnt.setValue(&UDE);
265  if (UDE.getName()) // Already have an entry with this inode, return it.
266    return &UDE;
267
268  // Otherwise, we don't have this directory yet, add it.  We use the string
269  // key from the DirEntries map as the string.
270  UDE.Name  = InterndDirName;
271  return &UDE;
272}
273
274/// getFile - Lookup, cache, and verify the specified file.  This returns null
275/// if the file doesn't exist.
276///
277const FileEntry *FileManager::getFile(llvm::StringRef Filename) {
278  ++NumFileLookups;
279
280  // See if there is already an entry in the map.
281  llvm::StringMapEntry<FileEntry *> &NamedFileEnt =
282    FileEntries.GetOrCreateValue(Filename);
283
284  // See if there is already an entry in the map.
285  if (NamedFileEnt.getValue())
286    return NamedFileEnt.getValue() == NON_EXISTENT_FILE
287                 ? 0 : NamedFileEnt.getValue();
288
289  ++NumFileCacheMisses;
290
291  // By default, initialize it to invalid.
292  NamedFileEnt.setValue(NON_EXISTENT_FILE);
293
294
295  // Get the null-terminated file name as stored as the key of the
296  // FileEntries map.
297  const char *InterndFileName = NamedFileEnt.getKeyData();
298
299
300  // Look up the directory for the file.  When looking up something like
301  // sys/foo.h we'll discover all of the search directories that have a 'sys'
302  // subdirectory.  This will let us avoid having to waste time on known-to-fail
303  // searches when we go to find sys/bar.h, because all the search directories
304  // without a 'sys' subdir will get a cached failure result.
305  const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename);
306  if (DirInfo == 0)  // Directory doesn't exist, file can't exist.
307    return 0;
308
309  // FIXME: Use the directory info to prune this, before doing the stat syscall.
310  // FIXME: This will reduce the # syscalls.
311
312  // Nope, there isn't.  Check to see if the file exists.
313  int FileDescriptor = -1;
314  struct stat StatBuf;
315  if (getStatValue(InterndFileName, StatBuf, &FileDescriptor))
316    return 0;
317
318  // It exists.  See if we have already opened a file with the same inode.
319  // This occurs when one dir is symlinked to another, for example.
320  FileEntry &UFE = UniqueFiles.getFile(InterndFileName, StatBuf);
321
322  NamedFileEnt.setValue(&UFE);
323  if (UFE.getName()) { // Already have an entry with this inode, return it.
324    // If the stat process opened the file, close it to avoid a FD leak.
325    if (FileDescriptor != -1)
326      close(FileDescriptor);
327
328    return &UFE;
329  }
330
331  // Otherwise, we don't have this directory yet, add it.
332  // FIXME: Change the name to be a char* that points back to the 'FileEntries'
333  // key.
334  UFE.Name    = InterndFileName;
335  UFE.Size    = StatBuf.st_size;
336  UFE.ModTime = StatBuf.st_mtime;
337  UFE.Dir     = DirInfo;
338  UFE.UID     = NextFileUID++;
339  UFE.FD      = FileDescriptor;
340  return &UFE;
341}
342
343const FileEntry *
344FileManager::getVirtualFile(llvm::StringRef Filename, off_t Size,
345                            time_t ModificationTime) {
346  ++NumFileLookups;
347
348  // See if there is already an entry in the map.
349  llvm::StringMapEntry<FileEntry *> &NamedFileEnt =
350    FileEntries.GetOrCreateValue(Filename);
351
352  // See if there is already an entry in the map.
353  if (NamedFileEnt.getValue() && NamedFileEnt.getValue() != NON_EXISTENT_FILE)
354    return NamedFileEnt.getValue();
355
356  ++NumFileCacheMisses;
357
358  // By default, initialize it to invalid.
359  NamedFileEnt.setValue(NON_EXISTENT_FILE);
360
361  // We allow the directory to not exist. If it does exist we store it.
362  FileEntry *UFE = 0;
363  const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename);
364  if (DirInfo) {
365    // Check to see if the file exists. If so, drop the virtual file
366    int FileDescriptor = -1;
367    struct stat StatBuf;
368    const char *InterndFileName = NamedFileEnt.getKeyData();
369    if (getStatValue(InterndFileName, StatBuf, &FileDescriptor) == 0) {
370      // If the stat process opened the file, close it to avoid a FD leak.
371      if (FileDescriptor != -1)
372        close(FileDescriptor);
373
374      StatBuf.st_size = Size;
375      StatBuf.st_mtime = ModificationTime;
376      UFE = &UniqueFiles.getFile(InterndFileName, StatBuf);
377
378      NamedFileEnt.setValue(UFE);
379
380      // If we had already opened this file, close it now so we don't
381      // leak the descriptor. We're not going to use the file
382      // descriptor anyway, since this is a virtual file.
383      if (UFE->FD != -1) {
384        close(UFE->FD);
385        UFE->FD = -1;
386      }
387
388      // If we already have an entry with this inode, return it.
389      if (UFE->getName())
390        return UFE;
391    }
392  }
393
394  if (!UFE) {
395    UFE = new FileEntry();
396    VirtualFileEntries.push_back(UFE);
397    NamedFileEnt.setValue(UFE);
398  }
399
400  // Get the null-terminated file name as stored as the key of the
401  // FileEntries map.
402  const char *InterndFileName = NamedFileEnt.getKeyData();
403
404  UFE->Name    = InterndFileName;
405  UFE->Size    = Size;
406  UFE->ModTime = ModificationTime;
407  UFE->Dir     = DirInfo;
408  UFE->UID     = NextFileUID++;
409  UFE->FD      = -1;
410  return UFE;
411}
412
413void FileManager::FixupRelativePath(llvm::sys::Path &path,
414                                    const FileSystemOptions &FSOpts) {
415  if (FSOpts.WorkingDir.empty() || llvm::sys::path::is_absolute(path.str()))
416    return;
417
418  llvm::SmallString<128> NewPath(FSOpts.WorkingDir);
419  llvm::sys::path::append(NewPath, path.str());
420  path = NewPath;
421}
422
423llvm::MemoryBuffer *FileManager::
424getBufferForFile(const FileEntry *Entry, std::string *ErrorStr) {
425  llvm::OwningPtr<llvm::MemoryBuffer> Result;
426  llvm::error_code ec;
427  if (FileSystemOpts.WorkingDir.empty()) {
428    const char *Filename = Entry->getName();
429    // If the file is already open, use the open file descriptor.
430    if (Entry->FD != -1) {
431      ec = llvm::MemoryBuffer::getOpenFile(Entry->FD, Filename, Result,
432                                           Entry->getSize());
433      if (ErrorStr)
434        *ErrorStr = ec.message();
435      // getOpenFile will have closed the file descriptor, don't reuse or
436      // reclose it.
437      Entry->FD = -1;
438      return Result.take();
439    }
440
441    // Otherwise, open the file.
442    ec = llvm::MemoryBuffer::getFile(Filename, Result, Entry->getSize());
443    if (ec && ErrorStr)
444      *ErrorStr = ec.message();
445    return Result.take();
446  }
447
448  llvm::sys::Path FilePath(Entry->getName());
449  FixupRelativePath(FilePath, FileSystemOpts);
450  ec = llvm::MemoryBuffer::getFile(FilePath.c_str(), Result, Entry->getSize());
451  if (ec && ErrorStr)
452    *ErrorStr = ec.message();
453  return Result.take();
454}
455
456llvm::MemoryBuffer *FileManager::
457getBufferForFile(llvm::StringRef Filename, std::string *ErrorStr) {
458  llvm::OwningPtr<llvm::MemoryBuffer> Result;
459  llvm::error_code ec;
460  if (FileSystemOpts.WorkingDir.empty()) {
461    ec = llvm::MemoryBuffer::getFile(Filename, Result);
462    if (ec && ErrorStr)
463      *ErrorStr = ec.message();
464    return Result.take();
465  }
466
467  llvm::sys::Path FilePath(Filename);
468  FixupRelativePath(FilePath, FileSystemOpts);
469  ec = llvm::MemoryBuffer::getFile(FilePath.c_str(), Result);
470  if (ec && ErrorStr)
471    *ErrorStr = ec.message();
472  return Result.take();
473}
474
475/// getStatValue - Get the 'stat' information for the specified path, using the
476/// cache to accelerate it if possible.  This returns true if the path does not
477/// exist or false if it exists.
478///
479/// The isForDir member indicates whether this is a directory lookup or not.
480/// This will return failure if the lookup isn't the expected kind.
481bool FileManager::getStatValue(const char *Path, struct stat &StatBuf,
482                               int *FileDescriptor) {
483  // FIXME: FileSystemOpts shouldn't be passed in here, all paths should be
484  // absolute!
485  if (FileSystemOpts.WorkingDir.empty())
486    return FileSystemStatCache::get(Path, StatBuf, FileDescriptor,
487                                    StatCache.get());
488
489  llvm::sys::Path FilePath(Path);
490  FixupRelativePath(FilePath, FileSystemOpts);
491
492  return FileSystemStatCache::get(FilePath.c_str(), StatBuf, FileDescriptor,
493                                  StatCache.get());
494}
495
496
497
498void FileManager::PrintStats() const {
499  llvm::errs() << "\n*** File Manager Stats:\n";
500  llvm::errs() << UniqueFiles.size() << " files found, "
501               << UniqueDirs.size() << " dirs found.\n";
502  llvm::errs() << NumDirLookups << " dir lookups, "
503               << NumDirCacheMisses << " dir cache misses.\n";
504  llvm::errs() << NumFileLookups << " file lookups, "
505               << NumFileCacheMisses << " file cache misses.\n";
506
507  //llvm::errs() << PagesMapped << BytesOfPagesMapped << FSLookups;
508}
509
510