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/FileSystemStatCache.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/Support/Path.h" 27 #include "llvm/Support/system_error.h" 28 #include "llvm/Config/config.h" 29 #include <map> 30 #include <set> 31 #include <string> 32 33 // FIXME: This is terrible, we need this for ::close. 34 #if !defined(_MSC_VER) && !defined(__MINGW32__) 35 #include <unistd.h> 36 #include <sys/uio.h> 37 #else 38 #include <io.h> 39 #endif 40 using namespace clang; 41 42 // FIXME: Enhance libsystem to support inode and other fields. 43 #include <sys/stat.h> 44 45 /// NON_EXISTENT_DIR - A special value distinct from null that is used to 46 /// represent a dir name that doesn't exist on the disk. 47 #define NON_EXISTENT_DIR reinterpret_cast<DirectoryEntry*>((intptr_t)-1) 48 49 /// NON_EXISTENT_FILE - A special value distinct from null that is used to 50 /// represent a filename that doesn't exist on the disk. 51 #define NON_EXISTENT_FILE reinterpret_cast<FileEntry*>((intptr_t)-1) 52 53 54 FileEntry::~FileEntry() { 55 // If this FileEntry owns an open file descriptor that never got used, close 56 // it. 57 if (FD != -1) ::close(FD); 58 } 59 60 //===----------------------------------------------------------------------===// 61 // Windows. 62 //===----------------------------------------------------------------------===// 63 64 #ifdef LLVM_ON_WIN32 65 66 #define IS_DIR_SEPARATOR_CHAR(x) ((x) == '/' || (x) == '\\') 67 68 namespace { 69 static std::string GetFullPath(const char *relPath) { 70 char *absPathStrPtr = _fullpath(NULL, relPath, 0); 71 assert(absPathStrPtr && "_fullpath() returned NULL!"); 72 73 std::string absPath(absPathStrPtr); 74 75 free(absPathStrPtr); 76 return absPath; 77 } 78 } 79 80 class FileManager::UniqueDirContainer { 81 /// UniqueDirs - Cache from full path to existing directories/files. 82 /// 83 llvm::StringMap<DirectoryEntry> UniqueDirs; 84 85 public: 86 DirectoryEntry &getDirectory(const char *Name, struct stat &StatBuf) { 87 std::string FullPath(GetFullPath(Name)); 88 return UniqueDirs.GetOrCreateValue(FullPath).getValue(); 89 } 90 91 size_t size() const { return UniqueDirs.size(); } 92 }; 93 94 class FileManager::UniqueFileContainer { 95 /// UniqueFiles - Cache from full path to existing directories/files. 96 /// 97 llvm::StringMap<FileEntry, llvm::BumpPtrAllocator> UniqueFiles; 98 99 public: 100 FileEntry &getFile(const char *Name, struct stat &StatBuf) { 101 std::string FullPath(GetFullPath(Name)); 102 103 // LowercaseString because Windows filesystem is case insensitive. 104 FullPath = llvm::LowercaseString(FullPath); 105 return UniqueFiles.GetOrCreateValue(FullPath).getValue(); 106 } 107 108 size_t size() const { return UniqueFiles.size(); } 109 }; 110 111 //===----------------------------------------------------------------------===// 112 // Unix-like Systems. 113 //===----------------------------------------------------------------------===// 114 115 #else 116 117 #define IS_DIR_SEPARATOR_CHAR(x) ((x) == '/') 118 119 class FileManager::UniqueDirContainer { 120 /// UniqueDirs - Cache from ID's to existing directories/files. 121 std::map<std::pair<dev_t, ino_t>, DirectoryEntry> UniqueDirs; 122 123 public: 124 DirectoryEntry &getDirectory(const char *Name, struct stat &StatBuf) { 125 return UniqueDirs[std::make_pair(StatBuf.st_dev, StatBuf.st_ino)]; 126 } 127 128 size_t size() const { return UniqueDirs.size(); } 129 }; 130 131 class FileManager::UniqueFileContainer { 132 /// UniqueFiles - Cache from ID's to existing directories/files. 133 std::set<FileEntry> UniqueFiles; 134 135 public: 136 FileEntry &getFile(const char *Name, struct stat &StatBuf) { 137 return 138 const_cast<FileEntry&>( 139 *UniqueFiles.insert(FileEntry(StatBuf.st_dev, 140 StatBuf.st_ino, 141 StatBuf.st_mode)).first); 142 } 143 144 size_t size() const { return UniqueFiles.size(); } 145 }; 146 147 #endif 148 149 //===----------------------------------------------------------------------===// 150 // Common logic. 151 //===----------------------------------------------------------------------===// 152 153 FileManager::FileManager(const FileSystemOptions &FSO) 154 : FileSystemOpts(FSO), 155 UniqueDirs(*new UniqueDirContainer()), 156 UniqueFiles(*new UniqueFileContainer()), 157 DirEntries(64), FileEntries(64), NextFileUID(0) { 158 NumDirLookups = NumFileLookups = 0; 159 NumDirCacheMisses = NumFileCacheMisses = 0; 160 } 161 162 FileManager::~FileManager() { 163 delete &UniqueDirs; 164 delete &UniqueFiles; 165 for (unsigned i = 0, e = VirtualFileEntries.size(); i != e; ++i) 166 delete VirtualFileEntries[i]; 167 } 168 169 void FileManager::addStatCache(FileSystemStatCache *statCache, 170 bool AtBeginning) { 171 assert(statCache && "No stat cache provided?"); 172 if (AtBeginning || StatCache.get() == 0) { 173 statCache->setNextStatCache(StatCache.take()); 174 StatCache.reset(statCache); 175 return; 176 } 177 178 FileSystemStatCache *LastCache = StatCache.get(); 179 while (LastCache->getNextStatCache()) 180 LastCache = LastCache->getNextStatCache(); 181 182 LastCache->setNextStatCache(statCache); 183 } 184 185 void FileManager::removeStatCache(FileSystemStatCache *statCache) { 186 if (!statCache) 187 return; 188 189 if (StatCache.get() == statCache) { 190 // This is the first stat cache. 191 StatCache.reset(StatCache->takeNextStatCache()); 192 return; 193 } 194 195 // Find the stat cache in the list. 196 FileSystemStatCache *PrevCache = StatCache.get(); 197 while (PrevCache && PrevCache->getNextStatCache() != statCache) 198 PrevCache = PrevCache->getNextStatCache(); 199 200 assert(PrevCache && "Stat cache not found for removal"); 201 PrevCache->setNextStatCache(statCache->getNextStatCache()); 202 } 203 204 /// \brief Retrieve the directory that the given file name resides in. 205 static const DirectoryEntry *getDirectoryFromFile(FileManager &FileMgr, 206 llvm::StringRef Filename) { 207 // Figure out what directory it is in. If the string contains a / in it, 208 // strip off everything after it. 209 // FIXME: this logic should be in sys::Path. 210 size_t SlashPos = Filename.size(); 211 while (SlashPos != 0 && !IS_DIR_SEPARATOR_CHAR(Filename[SlashPos-1])) 212 --SlashPos; 213 214 // Use the current directory if file has no path component. 215 if (SlashPos == 0) 216 return FileMgr.getDirectory("."); 217 218 if (SlashPos == Filename.size()-1) 219 return 0; // If filename ends with a /, it's a directory. 220 221 // Ignore repeated //'s. 222 while (SlashPos != 0 && IS_DIR_SEPARATOR_CHAR(Filename[SlashPos-1])) 223 --SlashPos; 224 225 return FileMgr.getDirectory(Filename.substr(0, SlashPos)); 226 } 227 228 /// getDirectory - Lookup, cache, and verify the specified directory. This 229 /// returns null if the directory doesn't exist. 230 /// 231 const DirectoryEntry *FileManager::getDirectory(llvm::StringRef Filename) { 232 // stat doesn't like trailing separators (at least on Windows). 233 if (Filename.size() > 1 && IS_DIR_SEPARATOR_CHAR(Filename.back())) 234 Filename = Filename.substr(0, Filename.size()-1); 235 236 ++NumDirLookups; 237 llvm::StringMapEntry<DirectoryEntry *> &NamedDirEnt = 238 DirEntries.GetOrCreateValue(Filename); 239 240 // See if there is already an entry in the map. 241 if (NamedDirEnt.getValue()) 242 return NamedDirEnt.getValue() == NON_EXISTENT_DIR 243 ? 0 : NamedDirEnt.getValue(); 244 245 ++NumDirCacheMisses; 246 247 // By default, initialize it to invalid. 248 NamedDirEnt.setValue(NON_EXISTENT_DIR); 249 250 // Get the null-terminated directory name as stored as the key of the 251 // DirEntries map. 252 const char *InterndDirName = NamedDirEnt.getKeyData(); 253 254 // Check to see if the directory exists. 255 struct stat StatBuf; 256 if (getStatValue(InterndDirName, StatBuf, 0/*directory lookup*/)) 257 return 0; 258 259 // It exists. See if we have already opened a directory with the same inode. 260 // This occurs when one dir is symlinked to another, for example. 261 DirectoryEntry &UDE = UniqueDirs.getDirectory(InterndDirName, StatBuf); 262 263 NamedDirEnt.setValue(&UDE); 264 if (UDE.getName()) // Already have an entry with this inode, return it. 265 return &UDE; 266 267 // Otherwise, we don't have this directory yet, add it. We use the string 268 // key from the DirEntries map as the string. 269 UDE.Name = InterndDirName; 270 return &UDE; 271 } 272 273 /// getFile - Lookup, cache, and verify the specified file. This returns null 274 /// if the file doesn't exist. 275 /// 276 const FileEntry *FileManager::getFile(llvm::StringRef Filename) { 277 ++NumFileLookups; 278 279 // See if there is already an entry in the map. 280 llvm::StringMapEntry<FileEntry *> &NamedFileEnt = 281 FileEntries.GetOrCreateValue(Filename); 282 283 // See if there is already an entry in the map. 284 if (NamedFileEnt.getValue()) 285 return NamedFileEnt.getValue() == NON_EXISTENT_FILE 286 ? 0 : NamedFileEnt.getValue(); 287 288 ++NumFileCacheMisses; 289 290 // By default, initialize it to invalid. 291 NamedFileEnt.setValue(NON_EXISTENT_FILE); 292 293 294 // Get the null-terminated file name as stored as the key of the 295 // FileEntries map. 296 const char *InterndFileName = NamedFileEnt.getKeyData(); 297 298 299 // Look up the directory for the file. When looking up something like 300 // sys/foo.h we'll discover all of the search directories that have a 'sys' 301 // subdirectory. This will let us avoid having to waste time on known-to-fail 302 // searches when we go to find sys/bar.h, because all the search directories 303 // without a 'sys' subdir will get a cached failure result. 304 const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename); 305 if (DirInfo == 0) // Directory doesn't exist, file can't exist. 306 return 0; 307 308 // FIXME: Use the directory info to prune this, before doing the stat syscall. 309 // FIXME: This will reduce the # syscalls. 310 311 // Nope, there isn't. Check to see if the file exists. 312 int FileDescriptor = -1; 313 struct stat StatBuf; 314 if (getStatValue(InterndFileName, StatBuf, &FileDescriptor)) 315 return 0; 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 // If the stat process opened the file, close it to avoid a FD leak. 324 if (FileDescriptor != -1) 325 close(FileDescriptor); 326 327 return &UFE; 328 } 329 330 // Otherwise, we don't have this directory yet, add it. 331 // FIXME: Change the name to be a char* that points back to the 'FileEntries' 332 // key. 333 UFE.Name = InterndFileName; 334 UFE.Size = StatBuf.st_size; 335 UFE.ModTime = StatBuf.st_mtime; 336 UFE.Dir = DirInfo; 337 UFE.UID = NextFileUID++; 338 UFE.FD = FileDescriptor; 339 return &UFE; 340 } 341 342 const FileEntry * 343 FileManager::getVirtualFile(llvm::StringRef Filename, off_t Size, 344 time_t ModificationTime) { 345 ++NumFileLookups; 346 347 // See if there is already an entry in the map. 348 llvm::StringMapEntry<FileEntry *> &NamedFileEnt = 349 FileEntries.GetOrCreateValue(Filename); 350 351 // See if there is already an entry in the map. 352 if (NamedFileEnt.getValue()) 353 return NamedFileEnt.getValue() == NON_EXISTENT_FILE 354 ? 0 : NamedFileEnt.getValue(); 355 356 ++NumFileCacheMisses; 357 358 // By default, initialize it to invalid. 359 NamedFileEnt.setValue(NON_EXISTENT_FILE); 360 361 const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename); 362 if (DirInfo == 0) // Directory doesn't exist, file can't exist. 363 return 0; 364 365 FileEntry *UFE = new FileEntry(); 366 VirtualFileEntries.push_back(UFE); 367 NamedFileEnt.setValue(UFE); 368 369 // Get the null-terminated file name as stored as the key of the 370 // FileEntries map. 371 const char *InterndFileName = NamedFileEnt.getKeyData(); 372 373 UFE->Name = InterndFileName; 374 UFE->Size = Size; 375 UFE->ModTime = ModificationTime; 376 UFE->Dir = DirInfo; 377 UFE->UID = NextFileUID++; 378 379 // If this virtual file resolves to a file, also map that file to the 380 // newly-created file entry. 381 int FileDescriptor = -1; 382 struct stat StatBuf; 383 if (getStatValue(InterndFileName, StatBuf, &FileDescriptor)) 384 return UFE; 385 386 UFE->FD = FileDescriptor; 387 llvm::sys::Path FilePath(UFE->Name); 388 FilePath.makeAbsolute(); 389 FileEntries[FilePath.str()] = UFE; 390 return UFE; 391 } 392 393 void FileManager::FixupRelativePath(llvm::sys::Path &path, 394 const FileSystemOptions &FSOpts) { 395 if (FSOpts.WorkingDir.empty() || path.isAbsolute()) return; 396 397 llvm::sys::Path NewPath(FSOpts.WorkingDir); 398 NewPath.appendComponent(path.str()); 399 path = NewPath; 400 } 401 402 llvm::MemoryBuffer *FileManager:: 403 getBufferForFile(const FileEntry *Entry, std::string *ErrorStr) { 404 llvm::error_code ec; 405 if (FileSystemOpts.WorkingDir.empty()) { 406 const char *Filename = Entry->getName(); 407 // If the file is already open, use the open file descriptor. 408 if (Entry->FD != -1) { 409 llvm::MemoryBuffer *Buf = 410 llvm::MemoryBuffer::getOpenFile(Entry->FD, Filename, ec, 411 Entry->getSize()); 412 if (Buf == 0 && ErrorStr) 413 *ErrorStr = ec.message(); 414 // getOpenFile will have closed the file descriptor, don't reuse or 415 // reclose it. 416 Entry->FD = -1; 417 return Buf; 418 } 419 420 // Otherwise, open the file. 421 llvm::MemoryBuffer *res = 422 llvm::MemoryBuffer::getFile(Filename, ec, Entry->getSize()); 423 if (res == 0 && ErrorStr) 424 *ErrorStr = ec.message(); 425 return res; 426 } 427 428 llvm::sys::Path FilePath(Entry->getName()); 429 FixupRelativePath(FilePath, FileSystemOpts); 430 llvm::MemoryBuffer *res = 431 llvm::MemoryBuffer::getFile(FilePath.c_str(), ec, Entry->getSize()); 432 if (res == 0 && ErrorStr) 433 *ErrorStr = ec.message(); 434 return res; 435 } 436 437 llvm::MemoryBuffer *FileManager:: 438 getBufferForFile(llvm::StringRef Filename, std::string *ErrorStr) { 439 llvm::error_code ec; 440 if (FileSystemOpts.WorkingDir.empty()) { 441 llvm::MemoryBuffer *res = llvm::MemoryBuffer::getFile(Filename, ec); 442 if (res == 0 && ErrorStr) 443 *ErrorStr = ec.message(); 444 return res; 445 } 446 447 llvm::sys::Path FilePath(Filename); 448 FixupRelativePath(FilePath, FileSystemOpts); 449 llvm::MemoryBuffer *res = llvm::MemoryBuffer::getFile(FilePath.c_str(), ec); 450 if (res == 0 && ErrorStr) 451 *ErrorStr = ec.message(); 452 return res; 453 } 454 455 /// getStatValue - Get the 'stat' information for the specified path, using the 456 /// cache to accelerate it if possible. This returns true if the path does not 457 /// exist or false if it exists. 458 /// 459 /// The isForDir member indicates whether this is a directory lookup or not. 460 /// This will return failure if the lookup isn't the expected kind. 461 bool FileManager::getStatValue(const char *Path, struct stat &StatBuf, 462 int *FileDescriptor) { 463 // FIXME: FileSystemOpts shouldn't be passed in here, all paths should be 464 // absolute! 465 if (FileSystemOpts.WorkingDir.empty()) 466 return FileSystemStatCache::get(Path, StatBuf, FileDescriptor, 467 StatCache.get()); 468 469 llvm::sys::Path FilePath(Path); 470 FixupRelativePath(FilePath, FileSystemOpts); 471 472 return FileSystemStatCache::get(FilePath.c_str(), StatBuf, FileDescriptor, 473 StatCache.get()); 474 } 475 476 477 478 void FileManager::PrintStats() const { 479 llvm::errs() << "\n*** File Manager Stats:\n"; 480 llvm::errs() << UniqueFiles.size() << " files found, " 481 << UniqueDirs.size() << " dirs found.\n"; 482 llvm::errs() << NumDirLookups << " dir lookups, " 483 << NumDirCacheMisses << " dir cache misses.\n"; 484 llvm::errs() << NumFileLookups << " file lookups, " 485 << NumFileCacheMisses << " file cache misses.\n"; 486 487 //llvm::errs() << PagesMapped << BytesOfPagesMapped << FSLookups; 488 } 489 490