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