FileManager.cpp revision 1eb4433ac451dc16f4133a88af2d002ac26c58ef
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 1525f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// getDirectory - Lookup, cache, and verify the specified directory. This 1535f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// returns null if the directory doesn't exist. 1541eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump/// 1555f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencerconst DirectoryEntry *FileManager::getDirectory(const char *NameStart, 1565f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer const char *NameEnd) { 1575f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer ++NumDirLookups; 1585f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt = 1595f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer DirEntries.GetOrCreateValue(NameStart, NameEnd); 1601eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1615f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // See if there is already an entry in the map. 1625f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer if (NamedDirEnt.getValue()) 1633d2da3d765123e15290c38ba44f4434462bb88d5Ted Kremenek return NamedDirEnt.getValue() == NON_EXISTENT_DIR 1645f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer ? 0 : NamedDirEnt.getValue(); 1651eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1665f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer ++NumDirCacheMisses; 1671eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1685f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // By default, initialize it to invalid. 1693d2da3d765123e15290c38ba44f4434462bb88d5Ted Kremenek NamedDirEnt.setValue(NON_EXISTENT_DIR); 1701eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1715f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // Get the null-terminated directory name as stored as the key of the 1725f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // DirEntries map. 1735f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer const char *InterndDirName = NamedDirEnt.getKeyData(); 1741eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1755f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // Check to see if the directory exists. 1765f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer struct stat StatBuf; 177fc7052d4a241ee6fc70afea7c1c9560147f0a49cTed Kremenek if (stat_cached(InterndDirName, &StatBuf) || // Error stat'ing. 1785f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer !S_ISDIR(StatBuf.st_mode)) // Not a directory? 1795f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer return 0; 1806bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek 1815f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // It exists. See if we have already opened a directory with the same inode. 1821eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump // This occurs when one dir is symlinked to another, for example. 1836bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek DirectoryEntry &UDE = UniqueDirs.getDirectory(InterndDirName, StatBuf); 1841eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1855f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer NamedDirEnt.setValue(&UDE); 1865f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer if (UDE.getName()) // Already have an entry with this inode, return it. 1875f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer return &UDE; 1881eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 1895f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // Otherwise, we don't have this directory yet, add it. We use the string 1905f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // key from the DirEntries map as the string. 1915f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer UDE.Name = InterndDirName; 1925f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer return &UDE; 1935f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer} 1945f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 1953d2da3d765123e15290c38ba44f4434462bb88d5Ted Kremenek/// NON_EXISTENT_FILE - A special value distinct from null that is used to 1965f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// represent a filename that doesn't exist on the disk. 1973d2da3d765123e15290c38ba44f4434462bb88d5Ted Kremenek#define NON_EXISTENT_FILE reinterpret_cast<FileEntry*>((intptr_t)-1) 1985f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 1995f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// getFile - Lookup, cache, and verify the specified file. This returns null 2005f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// if the file doesn't exist. 2011eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump/// 2025f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencerconst FileEntry *FileManager::getFile(const char *NameStart, 2035f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer const char *NameEnd) { 2045f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer ++NumFileLookups; 2051eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2065f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // See if there is already an entry in the map. 2075f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer llvm::StringMapEntry<FileEntry *> &NamedFileEnt = 2085f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer FileEntries.GetOrCreateValue(NameStart, NameEnd); 2095f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 2105f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // See if there is already an entry in the map. 2115f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer if (NamedFileEnt.getValue()) 2123d2da3d765123e15290c38ba44f4434462bb88d5Ted Kremenek return NamedFileEnt.getValue() == NON_EXISTENT_FILE 2135f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer ? 0 : NamedFileEnt.getValue(); 2141eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2155f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer ++NumFileCacheMisses; 2165f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 2175f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // By default, initialize it to invalid. 2183d2da3d765123e15290c38ba44f4434462bb88d5Ted Kremenek NamedFileEnt.setValue(NON_EXISTENT_FILE); 2195f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 2205f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // Figure out what directory it is in. If the string contains a / in it, 2215f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // strip off everything after it. 2225f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // FIXME: this logic should be in sys::Path. 2235f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer const char *SlashPos = NameEnd-1; 2246bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek while (SlashPos >= NameStart && !IS_DIR_SEPARATOR_CHAR(SlashPos[0])) 2255f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer --SlashPos; 22646730b261c46765c51a9aa83c2571a2a8705482aChris Lattner // Ignore duplicate //'s. 22746730b261c46765c51a9aa83c2571a2a8705482aChris Lattner while (SlashPos > NameStart && IS_DIR_SEPARATOR_CHAR(SlashPos[-1])) 22846730b261c46765c51a9aa83c2571a2a8705482aChris Lattner --SlashPos; 2291eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2305f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer const DirectoryEntry *DirInfo; 2315f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer if (SlashPos < NameStart) { 2325f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // Use the current directory if file has no path component. 2335f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer const char *Name = "."; 2345f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer DirInfo = getDirectory(Name, Name+1); 2355f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer } else if (SlashPos == NameEnd-1) 2365f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer return 0; // If filename ends with a /, it's a directory. 2375f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer else 2385f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer DirInfo = getDirectory(NameStart, SlashPos); 2391eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2405f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer if (DirInfo == 0) // Directory doesn't exist, file can't exist. 2415f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer return 0; 2421eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2435f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // Get the null-terminated file name as stored as the key of the 2445f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // FileEntries map. 2455f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer const char *InterndFileName = NamedFileEnt.getKeyData(); 2461eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2475f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // FIXME: Use the directory info to prune this, before doing the stat syscall. 2485f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // FIXME: This will reduce the # syscalls. 2491eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2505f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // Nope, there isn't. Check to see if the file exists. 2515f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer struct stat StatBuf; 2526cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer //llvm::errs() << "STATING: " << Filename; 253fc7052d4a241ee6fc70afea7c1c9560147f0a49cTed Kremenek if (stat_cached(InterndFileName, &StatBuf) || // Error stat'ing. 254fc7052d4a241ee6fc70afea7c1c9560147f0a49cTed Kremenek S_ISDIR(StatBuf.st_mode)) { // A directory? 2555f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // If this file doesn't exist, we leave a null in FileEntries for this path. 2566cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer //llvm::errs() << ": Not existing\n"; 2575f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer return 0; 2585f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer } 2596cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer //llvm::errs() << ": exists\n"; 2601eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 261bca6d125c77c93c7fa41798c15348175a6bb1267Ted Kremenek // It exists. See if we have already opened a file with the same inode. 2625f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // This occurs when one dir is symlinked to another, for example. 2636bb816a3b895e9c983d89b22d510dca58a0eb75eTed Kremenek FileEntry &UFE = UniqueFiles.getFile(InterndFileName, StatBuf); 2641eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2655f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer NamedFileEnt.setValue(&UFE); 2665f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer if (UFE.getName()) // Already have an entry with this inode, return it. 2675f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer return &UFE; 2685f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 2695f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // Otherwise, we don't have this directory yet, add it. 2705f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // FIXME: Change the name to be a char* that points back to the 'FileEntries' 2715f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer // key. 2725f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer UFE.Name = InterndFileName; 2735f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer UFE.Size = StatBuf.st_size; 2745f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer UFE.ModTime = StatBuf.st_mtime; 2755f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer UFE.Dir = DirInfo; 2765f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer UFE.UID = NextFileUID++; 2775f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer return &UFE; 2785f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer} 2795f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer 2805f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencervoid FileManager::PrintStats() const { 2816cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer llvm::errs() << "\n*** File Manager Stats:\n"; 2826cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer llvm::errs() << UniqueFiles.size() << " files found, " 2836cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer << UniqueDirs.size() << " dirs found.\n"; 2846cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer llvm::errs() << NumDirLookups << " dir lookups, " 2856cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer << NumDirCacheMisses << " dir cache misses.\n"; 2866cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer llvm::errs() << NumFileLookups << " file lookups, " 2876cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer << NumFileCacheMisses << " file cache misses.\n"; 2881eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2896cb7c1a43b0c8f739d1f54b7fdae5ede86033496Benjamin Kramer //llvm::errs() << PagesMapped << BytesOfPagesMapped << FSLookups; 2905f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer} 2914fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor 2924fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregorint MemorizeStatCalls::stat(const char *path, struct stat *buf) { 2934fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor int result = ::stat(path, buf); 2941eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 2951eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump if (result != 0) { 2964fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor // Cache failed 'stat' results. 2974fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor struct stat empty; 2984fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor StatCalls[path] = StatResult(result, empty); 2994fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor } 3004fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor else if (!S_ISDIR(buf->st_mode) || llvm::sys::Path(path).isAbsolute()) { 3014fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor // Cache file 'stat' results and directories with absolutely 3024fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor // paths. 3034fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor StatCalls[path] = StatResult(result, *buf); 3044fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor } 3051eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump 3061eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump return result; 3074fed3f47f6b9e31d603c5c2d1f6d8ec2e1241e57Douglas Gregor} 308