1 ///===--- FileManager.cpp - File System Probing and Caching ----------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file implements the FileManager interface. 11 // 12 //===----------------------------------------------------------------------===// 13 // 14 // TODO: This should index all interesting directories with dirent calls. 15 // getdirentries ? 16 // opendir/readdir_r/closedir ? 17 // 18 //===----------------------------------------------------------------------===// 19 20 #include "clang/Basic/FileManager.h" 21 #include "clang/Basic/FileSystemOptions.h" 22 #include "llvm/ADT/SmallString.h" 23 #include "llvm/ADT/StringExtras.h" 24 #include "llvm/Support/MemoryBuffer.h" 25 #include "llvm/Support/raw_ostream.h" 26 #include "llvm/System/Path.h" 27 #include "llvm/Config/config.h" 28 #include <map> 29 #include <set> 30 #include <string> 31 using namespace clang; 32 33 // FIXME: Enhance libsystem to support inode and other fields. 34 #include <sys/stat.h> 35 36 #if defined(_MSC_VER) 37 #define S_ISDIR(s) (_S_IFDIR & s) 38 #endif 39 40 /// NON_EXISTENT_DIR - A special value distinct from null that is used to 41 /// represent a dir name that doesn't exist on the disk. 42 #define NON_EXISTENT_DIR reinterpret_cast<DirectoryEntry*>((intptr_t)-1) 43 44 //===----------------------------------------------------------------------===// 45 // Windows. 46 //===----------------------------------------------------------------------===// 47 48 #ifdef LLVM_ON_WIN32 49 50 #define IS_DIR_SEPARATOR_CHAR(x) ((x) == '/' || (x) == '\\') 51 52 namespace { 53 static std::string GetFullPath(const char *relPath) { 54 char *absPathStrPtr = _fullpath(NULL, relPath, 0); 55 assert(absPathStrPtr && "_fullpath() returned NULL!"); 56 57 std::string absPath(absPathStrPtr); 58 59 free(absPathStrPtr); 60 return absPath; 61 } 62 } 63 64 class FileManager::UniqueDirContainer { 65 /// UniqueDirs - Cache from full path to existing directories/files. 66 /// 67 llvm::StringMap<DirectoryEntry> UniqueDirs; 68 69 public: 70 DirectoryEntry &getDirectory(const char *Name, struct stat &StatBuf) { 71 std::string FullPath(GetFullPath(Name)); 72 return UniqueDirs.GetOrCreateValue( 73 FullPath.c_str(), 74 FullPath.c_str() + FullPath.size() 75 ).getValue(); 76 } 77 78 size_t size() { return UniqueDirs.size(); } 79 }; 80 81 class FileManager::UniqueFileContainer { 82 /// UniqueFiles - Cache from full path to existing directories/files. 83 /// 84 llvm::StringMap<FileEntry, llvm::BumpPtrAllocator> UniqueFiles; 85 86 public: 87 FileEntry &getFile(const char *Name, struct stat &StatBuf) { 88 std::string FullPath(GetFullPath(Name)); 89 90 // LowercaseString because Windows filesystem is case insensitive. 91 FullPath = llvm::LowercaseString(FullPath); 92 return UniqueFiles.GetOrCreateValue( 93 FullPath.c_str(), 94 FullPath.c_str() + FullPath.size() 95 ).getValue(); 96 } 97 98 size_t size() { return UniqueFiles.size(); } 99 }; 100 101 //===----------------------------------------------------------------------===// 102 // Unix-like Systems. 103 //===----------------------------------------------------------------------===// 104 105 #else 106 107 #define IS_DIR_SEPARATOR_CHAR(x) ((x) == '/') 108 109 class FileManager::UniqueDirContainer { 110 /// UniqueDirs - Cache from ID's to existing directories/files. 111 /// 112 std::map<std::pair<dev_t, ino_t>, DirectoryEntry> UniqueDirs; 113 114 public: 115 DirectoryEntry &getDirectory(const char *Name, struct stat &StatBuf) { 116 return UniqueDirs[std::make_pair(StatBuf.st_dev, StatBuf.st_ino)]; 117 } 118 119 size_t size() { return UniqueDirs.size(); } 120 }; 121 122 class FileManager::UniqueFileContainer { 123 /// UniqueFiles - Cache from ID's to existing directories/files. 124 /// 125 std::set<FileEntry> UniqueFiles; 126 127 public: 128 FileEntry &getFile(const char *Name, struct stat &StatBuf) { 129 return 130 const_cast<FileEntry&>( 131 *UniqueFiles.insert(FileEntry(StatBuf.st_dev, 132 StatBuf.st_ino, 133 StatBuf.st_mode)).first); 134 } 135 136 size_t size() { return UniqueFiles.size(); } 137 }; 138 139 #endif 140 141 //===----------------------------------------------------------------------===// 142 // Common logic. 143 //===----------------------------------------------------------------------===// 144 145 FileManager::FileManager(const FileSystemOptions &FSO) 146 : FileSystemOpts(FSO), 147 UniqueDirs(*new UniqueDirContainer), 148 UniqueFiles(*new UniqueFileContainer), 149 DirEntries(64), FileEntries(64), NextFileUID(0) { 150 NumDirLookups = NumFileLookups = 0; 151 NumDirCacheMisses = NumFileCacheMisses = 0; 152 } 153 154 FileManager::~FileManager() { 155 delete &UniqueDirs; 156 delete &UniqueFiles; 157 for (llvm::SmallVectorImpl<FileEntry *>::iterator 158 V = VirtualFileEntries.begin(), 159 VEnd = VirtualFileEntries.end(); 160 V != VEnd; 161 ++V) 162 delete *V; 163 } 164 165 void FileManager::addStatCache(StatSysCallCache *statCache, bool AtBeginning) { 166 assert(statCache && "No stat cache provided?"); 167 if (AtBeginning || StatCache.get() == 0) { 168 statCache->setNextStatCache(StatCache.take()); 169 StatCache.reset(statCache); 170 return; 171 } 172 173 StatSysCallCache *LastCache = StatCache.get(); 174 while (LastCache->getNextStatCache()) 175 LastCache = LastCache->getNextStatCache(); 176 177 LastCache->setNextStatCache(statCache); 178 } 179 180 void FileManager::removeStatCache(StatSysCallCache *statCache) { 181 if (!statCache) 182 return; 183 184 if (StatCache.get() == statCache) { 185 // This is the first stat cache. 186 StatCache.reset(StatCache->takeNextStatCache()); 187 return; 188 } 189 190 // Find the stat cache in the list. 191 StatSysCallCache *PrevCache = StatCache.get(); 192 while (PrevCache && PrevCache->getNextStatCache() != statCache) 193 PrevCache = PrevCache->getNextStatCache(); 194 if (PrevCache) 195 PrevCache->setNextStatCache(statCache->getNextStatCache()); 196 else 197 assert(false && "Stat cache not found for removal"); 198 } 199 200 /// \brief Retrieve the directory that the given file name resides in. 201 static const DirectoryEntry *getDirectoryFromFile(FileManager &FileMgr, 202 llvm::StringRef Filename) { 203 // Figure out what directory it is in. If the string contains a / in it, 204 // strip off everything after it. 205 // FIXME: this logic should be in sys::Path. 206 size_t SlashPos = Filename.size(); 207 while (SlashPos != 0 && !IS_DIR_SEPARATOR_CHAR(Filename[SlashPos-1])) 208 --SlashPos; 209 210 // Use the current directory if file has no path component. 211 if (SlashPos == 0) 212 return FileMgr.getDirectory("."); 213 214 if (SlashPos == Filename.size()-1) 215 return 0; // If filename ends with a /, it's a directory. 216 217 // Ignore repeated //'s. 218 while (SlashPos != 0 && IS_DIR_SEPARATOR_CHAR(Filename[SlashPos-1])) 219 --SlashPos; 220 221 return FileMgr.getDirectory(Filename.substr(0, SlashPos)); 222 } 223 224 /// getDirectory - Lookup, cache, and verify the specified directory. This 225 /// returns null if the directory doesn't exist. 226 /// 227 const DirectoryEntry *FileManager::getDirectory(llvm::StringRef Filename) { 228 // stat doesn't like trailing separators (at least on Windows). 229 if (Filename.size() > 1 && IS_DIR_SEPARATOR_CHAR(Filename.back())) 230 Filename = Filename.substr(0, Filename.size()-1); 231 232 ++NumDirLookups; 233 llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt = 234 DirEntries.GetOrCreateValue(Filename); 235 236 // See if there is already an entry in the map. 237 if (NamedDirEnt.getValue()) 238 return NamedDirEnt.getValue() == NON_EXISTENT_DIR 239 ? 0 : NamedDirEnt.getValue(); 240 241 ++NumDirCacheMisses; 242 243 // By default, initialize it to invalid. 244 NamedDirEnt.setValue(NON_EXISTENT_DIR); 245 246 // Get the null-terminated directory name as stored as the key of the 247 // DirEntries map. 248 const char *InterndDirName = NamedDirEnt.getKeyData(); 249 250 // Check to see if the directory exists. 251 struct stat StatBuf; 252 if (stat_cached(InterndDirName, &StatBuf) || // Error stat'ing. 253 !S_ISDIR(StatBuf.st_mode)) // Not a directory? 254 return 0; 255 256 // It exists. See if we have already opened a directory with the same inode. 257 // This occurs when one dir is symlinked to another, for example. 258 DirectoryEntry &UDE = UniqueDirs.getDirectory(InterndDirName, StatBuf); 259 260 NamedDirEnt.setValue(&UDE); 261 if (UDE.getName()) // Already have an entry with this inode, return it. 262 return &UDE; 263 264 // Otherwise, we don't have this directory yet, add it. We use the string 265 // key from the DirEntries map as the string. 266 UDE.Name = InterndDirName; 267 return &UDE; 268 } 269 270 /// NON_EXISTENT_FILE - A special value distinct from null that is used to 271 /// represent a filename that doesn't exist on the disk. 272 #define NON_EXISTENT_FILE reinterpret_cast<FileEntry*>((intptr_t)-1) 273 274 /// getFile - Lookup, cache, and verify the specified file. This returns null 275 /// if the file doesn't exist. 276 /// 277 const 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 const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename); 300 if (DirInfo == 0) // Directory doesn't exist, file can't exist. 301 return 0; 302 303 // FIXME: Use the directory info to prune this, before doing the stat syscall. 304 // FIXME: This will reduce the # syscalls. 305 306 // Nope, there isn't. Check to see if the file exists. 307 struct stat StatBuf; 308 //llvm::errs() << "STATING: " << Filename; 309 if (stat_cached(InterndFileName, &StatBuf) || // Error stat'ing. 310 S_ISDIR(StatBuf.st_mode)) { // A directory? 311 // If this file doesn't exist, we leave a null in FileEntries for this path. 312 //llvm::errs() << ": Not existing\n"; 313 return 0; 314 } 315 //llvm::errs() << ": exists\n"; 316 317 // It exists. See if we have already opened a file with the same inode. 318 // This occurs when one dir is symlinked to another, for example. 319 FileEntry &UFE = UniqueFiles.getFile(InterndFileName, StatBuf); 320 321 NamedFileEnt.setValue(&UFE); 322 if (UFE.getName()) // Already have an entry with this inode, return it. 323 return &UFE; 324 325 // Otherwise, we don't have this directory yet, add it. 326 // FIXME: Change the name to be a char* that points back to the 'FileEntries' 327 // key. 328 UFE.Name = InterndFileName; 329 UFE.Size = StatBuf.st_size; 330 UFE.ModTime = StatBuf.st_mtime; 331 UFE.Dir = DirInfo; 332 UFE.UID = NextFileUID++; 333 return &UFE; 334 } 335 336 const FileEntry * 337 FileManager::getVirtualFile(llvm::StringRef Filename, off_t Size, 338 time_t ModificationTime) { 339 ++NumFileLookups; 340 341 // See if there is already an entry in the map. 342 llvm::StringMapEntry<FileEntry *> &NamedFileEnt = 343 FileEntries.GetOrCreateValue(Filename); 344 345 // See if there is already an entry in the map. 346 if (NamedFileEnt.getValue()) 347 return NamedFileEnt.getValue() == NON_EXISTENT_FILE 348 ? 0 : NamedFileEnt.getValue(); 349 350 ++NumFileCacheMisses; 351 352 // By default, initialize it to invalid. 353 NamedFileEnt.setValue(NON_EXISTENT_FILE); 354 355 const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename); 356 if (DirInfo == 0) // Directory doesn't exist, file can't exist. 357 return 0; 358 359 FileEntry *UFE = new FileEntry(); 360 VirtualFileEntries.push_back(UFE); 361 NamedFileEnt.setValue(UFE); 362 363 UFE->Name = NamedFileEnt.getKeyData(); 364 UFE->Size = Size; 365 UFE->ModTime = ModificationTime; 366 UFE->Dir = DirInfo; 367 UFE->UID = NextFileUID++; 368 369 // If this virtual file resolves to a file, also map that file to the 370 // newly-created file entry. 371 const char *InterndFileName = NamedFileEnt.getKeyData(); 372 struct stat StatBuf; 373 if (!stat_cached(InterndFileName, &StatBuf) && 374 !S_ISDIR(StatBuf.st_mode)) { 375 llvm::sys::Path FilePath(InterndFileName); 376 FilePath.makeAbsolute(); 377 FileEntries[FilePath.str()] = UFE; 378 } 379 380 return UFE; 381 } 382 383 void FileManager::FixupRelativePath(llvm::sys::Path &path, 384 const FileSystemOptions &FSOpts) { 385 if (FSOpts.WorkingDir.empty() || path.isAbsolute()) return; 386 387 llvm::sys::Path NewPath(FSOpts.WorkingDir); 388 NewPath.appendComponent(path.str()); 389 path = NewPath; 390 } 391 392 llvm::MemoryBuffer *FileManager:: 393 getBufferForFile(const FileEntry *Entry, std::string *ErrorStr) { 394 llvm::StringRef Filename = Entry->getName(); 395 if (FileSystemOpts.WorkingDir.empty()) 396 return llvm::MemoryBuffer::getFile(Filename, ErrorStr); 397 398 llvm::sys::Path FilePath(Filename); 399 FixupRelativePath(FilePath, FileSystemOpts); 400 return llvm::MemoryBuffer::getFile(FilePath.c_str(), ErrorStr); 401 } 402 403 llvm::MemoryBuffer *FileManager:: 404 getBufferForFile(llvm::StringRef Filename, std::string *ErrorStr) { 405 if (FileSystemOpts.WorkingDir.empty()) 406 return llvm::MemoryBuffer::getFile(Filename, ErrorStr); 407 408 llvm::sys::Path FilePath(Filename); 409 FixupRelativePath(FilePath, FileSystemOpts); 410 return llvm::MemoryBuffer::getFile(FilePath.c_str(), ErrorStr); 411 } 412 413 int FileManager::stat_cached(const char *path, struct stat *buf) { 414 if (FileSystemOpts.WorkingDir.empty()) 415 return StatCache.get() ? StatCache->stat(path, buf) : stat(path, buf); 416 417 llvm::sys::Path FilePath(path); 418 FixupRelativePath(FilePath, FileSystemOpts); 419 420 return StatCache.get() ? StatCache->stat(FilePath.c_str(), buf) 421 : stat(FilePath.c_str(), buf); 422 } 423 424 void FileManager::PrintStats() const { 425 llvm::errs() << "\n*** File Manager Stats:\n"; 426 llvm::errs() << UniqueFiles.size() << " files found, " 427 << UniqueDirs.size() << " dirs found.\n"; 428 llvm::errs() << NumDirLookups << " dir lookups, " 429 << NumDirCacheMisses << " dir cache misses.\n"; 430 llvm::errs() << NumFileLookups << " file lookups, " 431 << NumFileCacheMisses << " file cache misses.\n"; 432 433 //llvm::errs() << PagesMapped << BytesOfPagesMapped << FSLookups; 434 } 435 436 int MemorizeStatCalls::stat(const char *path, struct stat *buf) { 437 int result = StatSysCallCache::stat(path, buf); 438 439 // Do not cache failed stats, it is easy to construct common inconsistent 440 // situations if we do, and they are not important for PCH performance (which 441 // currently only needs the stats to construct the initial FileManager 442 // entries). 443 if (result != 0) 444 return result; 445 446 // Cache file 'stat' results and directories with absolutely paths. 447 if (!S_ISDIR(buf->st_mode) || llvm::sys::Path(path).isAbsolute()) 448 StatCalls[path] = StatResult(result, *buf); 449 450 return result; 451 } 452