FileManager.cpp revision 458fb10ef5ba2d7b375c6c64095c1458af0a5be3
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 { 506bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek static std::string GetFullPath(const char *relPath) 516bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek { 526bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek char *absPathStrPtr = _fullpath(NULL, relPath, 0); 536bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek assert(absPathStrPtr && "_fullpath() returned NULL!"); 546bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek 556bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek std::string absPath(absPathStrPtr); 566bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek 576bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek free(absPathStrPtr); 586bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek return absPath; 596bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek } 606bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek} 616bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek 626bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenekclass FileManager::UniqueDirContainer { 636bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek /// UniqueDirs - Cache from full path to existing directories/files. 646bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek /// 656bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek llvm::StringMap<DirectoryEntry> UniqueDirs; 666bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek 676bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenekpublic: 686bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek DirectoryEntry &getDirectory(const char *Name, struct stat &StatBuf) { 696bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek std::string FullPath(GetFullPath(Name)); 706bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek return UniqueDirs.GetOrCreateValue( 716bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek FullPath.c_str(), 726bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek FullPath.c_str() + FullPath.size() 736bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek ).getValue(); 746bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek } 756bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek 766bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek size_t size() { return UniqueDirs.size(); } 776bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek}; 786bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek 796bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenekclass FileManager::UniqueFileContainer { 806bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek /// UniqueFiles - Cache from full path to existing directories/files. 816bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek /// 8275368893339d89f6523c312b0a0eb23d438b6dffTed Kremenek llvm::StringMap<FileEntry, llvm::BumpPtrAllocator> UniqueFiles; 836bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek 846bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenekpublic: 856bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek FileEntry &getFile(const char *Name, struct stat &StatBuf) { 866bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek std::string FullPath(GetFullPath(Name)); 876bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek return UniqueFiles.GetOrCreateValue( 886bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek FullPath.c_str(), 896bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek FullPath.c_str() + FullPath.size() 906bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek ).getValue(); 916bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek } 926bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek 936bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek size_t size() { return UniqueFiles.size(); } 946bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek}; 956bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek 96cb8d58b82859d2c56b679b901de38f416e2b6f48Ted Kremenek//===----------------------------------------------------------------------===// 97cb8d58b82859d2c56b679b901de38f416e2b6f48Ted Kremenek// Unix-like Systems. 98cb8d58b82859d2c56b679b901de38f416e2b6f48Ted Kremenek//===----------------------------------------------------------------------===// 99cb8d58b82859d2c56b679b901de38f416e2b6f48Ted Kremenek 1006bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek#else 1016bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek 1026bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek#define IS_DIR_SEPARATOR_CHAR(x) ((x) == '/') 1036bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek 1046bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenekclass FileManager::UniqueDirContainer { 1056bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek /// UniqueDirs - Cache from ID's to existing directories/files. 1066bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek /// 1076bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek std::map<std::pair<dev_t, ino_t>, DirectoryEntry> UniqueDirs; 1086bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek 1096bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenekpublic: 1106bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek DirectoryEntry &getDirectory(const char *Name, struct stat &StatBuf) { 1116bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek return UniqueDirs[std::make_pair(StatBuf.st_dev, StatBuf.st_ino)]; 1126bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek } 1136bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek 1146bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek size_t size() { return UniqueDirs.size(); } 1156bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek}; 1166bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek 1176bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenekclass FileManager::UniqueFileContainer { 1186bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek /// UniqueFiles - Cache from ID's to existing directories/files. 1196bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek /// 1206bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek std::set<FileEntry> UniqueFiles; 1216bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek 1226bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenekpublic: 1236bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek FileEntry &getFile(const char *Name, struct stat &StatBuf) { 1246bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek return 1256bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek const_cast<FileEntry&>( 1266bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek *UniqueFiles.insert(FileEntry(StatBuf.st_dev, 12796438f319bb07d9a40564b5e01333f82c0c8a61eTed Kremenek StatBuf.st_ino, 12896438f319bb07d9a40564b5e01333f82c0c8a61eTed Kremenek StatBuf.st_mode)).first); 1296bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek } 1306bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek 1316bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek size_t size() { return UniqueFiles.size(); } 1326bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek}; 1336bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek 1346bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek#endif 1356bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek 136cb8d58b82859d2c56b679b901de38f416e2b6f48Ted Kremenek//===----------------------------------------------------------------------===// 137cb8d58b82859d2c56b679b901de38f416e2b6f48Ted Kremenek// Common logic. 138cb8d58b82859d2c56b679b901de38f416e2b6f48Ted Kremenek//===----------------------------------------------------------------------===// 1396bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek 14096438f319bb07d9a40564b5e01333f82c0c8a61eTed KremenekFileManager::FileManager() 141fc7052d4a241ee6fc70afea7c1c9560147f0a49cTed Kremenek : UniqueDirs(*new UniqueDirContainer), 142fc7052d4a241ee6fc70afea7c1c9560147f0a49cTed Kremenek UniqueFiles(*new UniqueFileContainer), 14396438f319bb07d9a40564b5e01333f82c0c8a61eTed Kremenek DirEntries(64), FileEntries(64), NextFileUID(0) { 1446bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek NumDirLookups = NumFileLookups = 0; 1456bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek NumDirCacheMisses = NumFileCacheMisses = 0; 1466bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek} 1476bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek 1486bb816a3b895e9c983d89b22d510dca58a0eb75eTed KremenekFileManager::~FileManager() { 1496bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek delete &UniqueDirs; 1506bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek delete &UniqueFiles; 1516bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek} 1526bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek 1535f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// getDirectory - Lookup, cache, and verify the specified directory. This 1545f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// returns null if the directory doesn't exist. 1555f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// 1565f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencerconst DirectoryEntry *FileManager::getDirectory(const char *NameStart, 1575f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer const char *NameEnd) { 1585f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer ++NumDirLookups; 1595f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt = 1605f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer DirEntries.GetOrCreateValue(NameStart, NameEnd); 1615f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 1625f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // See if there is already an entry in the map. 1635f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer if (NamedDirEnt.getValue()) 1643d2da3d765123e15290c38ba44f4434462bb88d5Ted Kremenek return NamedDirEnt.getValue() == NON_EXISTENT_DIR 1655f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer ? 0 : NamedDirEnt.getValue(); 1665f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 1675f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer ++NumDirCacheMisses; 1685f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 1695f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // By default, initialize it to invalid. 1703d2da3d765123e15290c38ba44f4434462bb88d5Ted Kremenek NamedDirEnt.setValue(NON_EXISTENT_DIR); 1715f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 1725f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // Get the null-terminated directory name as stored as the key of the 1735f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // DirEntries map. 1745f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer const char *InterndDirName = NamedDirEnt.getKeyData(); 1755f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 1765f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // Check to see if the directory exists. 1775f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer struct stat StatBuf; 178fc7052d4a241ee6fc70afea7c1c9560147f0a49cTed Kremenek if (stat_cached(InterndDirName, &StatBuf) || // Error stat'ing. 1795f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer !S_ISDIR(StatBuf.st_mode)) // Not a directory? 1805f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer return 0; 1816bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek 1825f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // It exists. See if we have already opened a directory with the same inode. 183da9954400aab56bc3df60eb1b7be2489121c6166Ted Kremenek // This occurs when one dir is symlinked to another, for example. 1846bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek DirectoryEntry &UDE = UniqueDirs.getDirectory(InterndDirName, StatBuf); 1855f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 1865f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer NamedDirEnt.setValue(&UDE); 1875f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer if (UDE.getName()) // Already have an entry with this inode, return it. 1885f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer return &UDE; 1895f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 1905f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // Otherwise, we don't have this directory yet, add it. We use the string 1915f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // key from the DirEntries map as the string. 1925f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer UDE.Name = InterndDirName; 1935f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer return &UDE; 1945f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer} 1955f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 1963d2da3d765123e15290c38ba44f4434462bb88d5Ted Kremenek/// NON_EXISTENT_FILE - A special value distinct from null that is used to 1975f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// represent a filename that doesn't exist on the disk. 1983d2da3d765123e15290c38ba44f4434462bb88d5Ted Kremenek#define NON_EXISTENT_FILE reinterpret_cast<FileEntry*>((intptr_t)-1) 1995f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 2005f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// getFile - Lookup, cache, and verify the specified file. This returns null 2015f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// if the file doesn't exist. 2025f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// 2035f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencerconst FileEntry *FileManager::getFile(const char *NameStart, 2045f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer const char *NameEnd) { 2055f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer ++NumFileLookups; 2065f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 2075f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // See if there is already an entry in the map. 2085f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer llvm::StringMapEntry<FileEntry *> &NamedFileEnt = 2095f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer FileEntries.GetOrCreateValue(NameStart, NameEnd); 2105f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 2115f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // See if there is already an entry in the map. 2125f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer if (NamedFileEnt.getValue()) 2133d2da3d765123e15290c38ba44f4434462bb88d5Ted Kremenek return NamedFileEnt.getValue() == NON_EXISTENT_FILE 2145f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer ? 0 : NamedFileEnt.getValue(); 2155f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 2165f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer ++NumFileCacheMisses; 2175f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 2185f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // By default, initialize it to invalid. 2193d2da3d765123e15290c38ba44f4434462bb88d5Ted Kremenek NamedFileEnt.setValue(NON_EXISTENT_FILE); 2205f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 2215f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // Figure out what directory it is in. If the string contains a / in it, 2225f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // strip off everything after it. 2235f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // FIXME: this logic should be in sys::Path. 2245f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer const char *SlashPos = NameEnd-1; 2256bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek while (SlashPos >= NameStart && !IS_DIR_SEPARATOR_CHAR(SlashPos[0])) 2265f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer --SlashPos; 22746730b261c46765c51a9aa83c2571a2a8705482aChris Lattner // Ignore duplicate //'s. 22846730b261c46765c51a9aa83c2571a2a8705482aChris Lattner while (SlashPos > NameStart && IS_DIR_SEPARATOR_CHAR(SlashPos[-1])) 22946730b261c46765c51a9aa83c2571a2a8705482aChris Lattner --SlashPos; 2305f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 2315f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer const DirectoryEntry *DirInfo; 2325f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer if (SlashPos < NameStart) { 2335f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // Use the current directory if file has no path component. 2345f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer const char *Name = "."; 2355f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer DirInfo = getDirectory(Name, Name+1); 2365f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer } else if (SlashPos == NameEnd-1) 2375f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer return 0; // If filename ends with a /, it's a directory. 2385f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer else 2395f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer DirInfo = getDirectory(NameStart, SlashPos); 2405f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 2415f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer if (DirInfo == 0) // Directory doesn't exist, file can't exist. 2425f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer return 0; 2435f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 2445f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // Get the null-terminated file name as stored as the key of the 2455f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // FileEntries map. 2465f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer const char *InterndFileName = NamedFileEnt.getKeyData(); 2475f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 2485f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // FIXME: Use the directory info to prune this, before doing the stat syscall. 2495f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // FIXME: This will reduce the # syscalls. 2505f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 2515f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // Nope, there isn't. Check to see if the file exists. 2525f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer struct stat StatBuf; 2536cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer //llvm::errs() << "STATING: " << Filename; 254fc7052d4a241ee6fc70afea7c1c9560147f0a49cTed Kremenek if (stat_cached(InterndFileName, &StatBuf) || // Error stat'ing. 255fc7052d4a241ee6fc70afea7c1c9560147f0a49cTed Kremenek S_ISDIR(StatBuf.st_mode)) { // A directory? 2565f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // If this file doesn't exist, we leave a null in FileEntries for this path. 2576cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer //llvm::errs() << ": Not existing\n"; 2585f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer return 0; 2595f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer } 2606cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer //llvm::errs() << ": exists\n"; 2615f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 262bca6d125c77c93c7fa41798c15348175a6bb1267Ted Kremenek // It exists. See if we have already opened a file with the same inode. 2635f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // This occurs when one dir is symlinked to another, for example. 2646bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek FileEntry &UFE = UniqueFiles.getFile(InterndFileName, StatBuf); 2655f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 2665f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer NamedFileEnt.setValue(&UFE); 2675f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer if (UFE.getName()) // Already have an entry with this inode, return it. 2685f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer return &UFE; 2695f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 2705f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // Otherwise, we don't have this directory yet, add it. 2715f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // FIXME: Change the name to be a char* that points back to the 'FileEntries' 2725f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // key. 2735f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer UFE.Name = InterndFileName; 2745f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer UFE.Size = StatBuf.st_size; 2755f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer UFE.ModTime = StatBuf.st_mtime; 2765f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer UFE.Dir = DirInfo; 2775f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer UFE.UID = NextFileUID++; 2785f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer return &UFE; 2795f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer} 2805f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 2815f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencervoid FileManager::PrintStats() const { 2826cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer llvm::errs() << "\n*** File Manager Stats:\n"; 2836cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer llvm::errs() << UniqueFiles.size() << " files found, " 2846cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer << UniqueDirs.size() << " dirs found.\n"; 2856cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer llvm::errs() << NumDirLookups << " dir lookups, " 2866cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer << NumDirCacheMisses << " dir cache misses.\n"; 2876cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer llvm::errs() << NumFileLookups << " file lookups, " 2886cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer << NumFileCacheMisses << " file cache misses.\n"; 2893d2da3d765123e15290c38ba44f4434462bb88d5Ted Kremenek 2906cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer //llvm::errs() << PagesMapped << BytesOfPagesMapped << FSLookups; 2915f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer} 2924fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor 2934fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregorint MemorizeStatCalls::stat(const char *path, struct stat *buf) { 2944fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor int result = ::stat(path, buf); 2954fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor 2964fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor if (result != 0) { 2974fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor // Cache failed 'stat' results. 2984fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor struct stat empty; 2994fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor StatCalls[path] = StatResult(result, empty); 3004fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor } 3014fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor else if (!S_ISDIR(buf->st_mode) || llvm::sys::Path(path).isAbsolute()) { 3024fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor // Cache file 'stat' results and directories with absolutely 3034fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor // paths. 3044fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor StatCalls[path] = StatResult(result, *buf); 3054fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor } 3064fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor 3074fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor return result; 3084fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor} 309