1 //===--- FileManager.cpp - File System Probing and Caching ----------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements the FileManager interface. 10 // 11 //===----------------------------------------------------------------------===// 12 // 13 // TODO: This should index all interesting directories with dirent calls. 14 // getdirentries ? 15 // opendir/readdir_r/closedir ? 16 // 17 //===----------------------------------------------------------------------===// 18 19 #include "clang/Basic/FileManager.h" 20 #include "clang/Basic/FileSystemStatCache.h" 21 #include "llvm/ADT/STLExtras.h" 22 #include "llvm/ADT/SmallString.h" 23 #include "llvm/ADT/Statistic.h" 24 #include "llvm/Config/llvm-config.h" 25 #include "llvm/Support/FileSystem.h" 26 #include "llvm/Support/MemoryBuffer.h" 27 #include "llvm/Support/Path.h" 28 #include "llvm/Support/raw_ostream.h" 29 #include <algorithm> 30 #include <cassert> 31 #include <climits> 32 #include <cstdint> 33 #include <cstdlib> 34 #include <optional> 35 #include <string> 36 #include <utility> 37 38 using namespace clang; 39 40 #define DEBUG_TYPE "file-search" 41 42 //===----------------------------------------------------------------------===// 43 // Common logic. 44 //===----------------------------------------------------------------------===// 45 46 FileManager::FileManager(const FileSystemOptions &FSO, 47 IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) 48 : FS(std::move(FS)), FileSystemOpts(FSO), SeenDirEntries(64), 49 SeenFileEntries(64), NextFileUID(0) { 50 // If the caller doesn't provide a virtual file system, just grab the real 51 // file system. 52 if (!this->FS) 53 this->FS = llvm::vfs::getRealFileSystem(); 54 } 55 56 FileManager::~FileManager() = default; 57 58 void FileManager::setStatCache(std::unique_ptr<FileSystemStatCache> statCache) { 59 assert(statCache && "No stat cache provided?"); 60 StatCache = std::move(statCache); 61 } 62 63 void FileManager::clearStatCache() { StatCache.reset(); } 64 65 /// Retrieve the directory that the given file name resides in. 66 /// Filename can point to either a real file or a virtual file. 67 static llvm::Expected<DirectoryEntryRef> 68 getDirectoryFromFile(FileManager &FileMgr, StringRef Filename, 69 bool CacheFailure) { 70 if (Filename.empty()) 71 return llvm::errorCodeToError( 72 make_error_code(std::errc::no_such_file_or_directory)); 73 74 if (llvm::sys::path::is_separator(Filename[Filename.size() - 1])) 75 return llvm::errorCodeToError(make_error_code(std::errc::is_a_directory)); 76 77 StringRef DirName = llvm::sys::path::parent_path(Filename); 78 // Use the current directory if file has no path component. 79 if (DirName.empty()) 80 DirName = "."; 81 82 return FileMgr.getDirectoryRef(DirName, CacheFailure); 83 } 84 85 /// Add all ancestors of the given path (pointing to either a file or 86 /// a directory) as virtual directories. 87 void FileManager::addAncestorsAsVirtualDirs(StringRef Path) { 88 StringRef DirName = llvm::sys::path::parent_path(Path); 89 if (DirName.empty()) 90 DirName = "."; 91 92 auto &NamedDirEnt = *SeenDirEntries.insert( 93 {DirName, std::errc::no_such_file_or_directory}).first; 94 95 // When caching a virtual directory, we always cache its ancestors 96 // at the same time. Therefore, if DirName is already in the cache, 97 // we don't need to recurse as its ancestors must also already be in 98 // the cache (or it's a known non-virtual directory). 99 if (NamedDirEnt.second) 100 return; 101 102 // Add the virtual directory to the cache. 103 auto *UDE = new (DirsAlloc.Allocate()) DirectoryEntry(); 104 NamedDirEnt.second = *UDE; 105 VirtualDirectoryEntries.push_back(UDE); 106 107 // Recursively add the other ancestors. 108 addAncestorsAsVirtualDirs(DirName); 109 } 110 111 llvm::Expected<DirectoryEntryRef> 112 FileManager::getDirectoryRef(StringRef DirName, bool CacheFailure) { 113 // stat doesn't like trailing separators except for root directory. 114 // At least, on Win32 MSVCRT, stat() cannot strip trailing '/'. 115 // (though it can strip '\\') 116 if (DirName.size() > 1 && 117 DirName != llvm::sys::path::root_path(DirName) && 118 llvm::sys::path::is_separator(DirName.back())) 119 DirName = DirName.substr(0, DirName.size()-1); 120 std::optional<std::string> DirNameStr; 121 if (is_style_windows(llvm::sys::path::Style::native)) { 122 // Fixing a problem with "clang C:test.c" on Windows. 123 // Stat("C:") does not recognize "C:" as a valid directory 124 if (DirName.size() > 1 && DirName.back() == ':' && 125 DirName.equals_insensitive(llvm::sys::path::root_name(DirName))) { 126 DirNameStr = DirName.str() + '.'; 127 DirName = *DirNameStr; 128 } 129 } 130 131 ++NumDirLookups; 132 133 // See if there was already an entry in the map. Note that the map 134 // contains both virtual and real directories. 135 auto SeenDirInsertResult = 136 SeenDirEntries.insert({DirName, std::errc::no_such_file_or_directory}); 137 if (!SeenDirInsertResult.second) { 138 if (SeenDirInsertResult.first->second) 139 return DirectoryEntryRef(*SeenDirInsertResult.first); 140 return llvm::errorCodeToError(SeenDirInsertResult.first->second.getError()); 141 } 142 143 // We've not seen this before. Fill it in. 144 ++NumDirCacheMisses; 145 auto &NamedDirEnt = *SeenDirInsertResult.first; 146 assert(!NamedDirEnt.second && "should be newly-created"); 147 148 // Get the null-terminated directory name as stored as the key of the 149 // SeenDirEntries map. 150 StringRef InterndDirName = NamedDirEnt.first(); 151 152 // Check to see if the directory exists. 153 llvm::vfs::Status Status; 154 auto statError = getStatValue(InterndDirName, Status, false, 155 nullptr /*directory lookup*/); 156 if (statError) { 157 // There's no real directory at the given path. 158 if (CacheFailure) 159 NamedDirEnt.second = statError; 160 else 161 SeenDirEntries.erase(DirName); 162 return llvm::errorCodeToError(statError); 163 } 164 165 // It exists. See if we have already opened a directory with the 166 // same inode (this occurs on Unix-like systems when one dir is 167 // symlinked to another, for example) or the same path (on 168 // Windows). 169 DirectoryEntry *&UDE = UniqueRealDirs[Status.getUniqueID()]; 170 171 if (!UDE) { 172 // We don't have this directory yet, add it. We use the string 173 // key from the SeenDirEntries map as the string. 174 UDE = new (DirsAlloc.Allocate()) DirectoryEntry(); 175 } 176 NamedDirEnt.second = *UDE; 177 178 return DirectoryEntryRef(NamedDirEnt); 179 } 180 181 llvm::ErrorOr<const DirectoryEntry *> 182 FileManager::getDirectory(StringRef DirName, bool CacheFailure) { 183 auto Result = getDirectoryRef(DirName, CacheFailure); 184 if (Result) 185 return &Result->getDirEntry(); 186 return llvm::errorToErrorCode(Result.takeError()); 187 } 188 189 llvm::ErrorOr<const FileEntry *> 190 FileManager::getFile(StringRef Filename, bool openFile, bool CacheFailure) { 191 auto Result = getFileRef(Filename, openFile, CacheFailure); 192 if (Result) 193 return &Result->getFileEntry(); 194 return llvm::errorToErrorCode(Result.takeError()); 195 } 196 197 llvm::Expected<FileEntryRef> 198 FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) { 199 ++NumFileLookups; 200 201 // See if there is already an entry in the map. 202 auto SeenFileInsertResult = 203 SeenFileEntries.insert({Filename, std::errc::no_such_file_or_directory}); 204 if (!SeenFileInsertResult.second) { 205 if (!SeenFileInsertResult.first->second) 206 return llvm::errorCodeToError( 207 SeenFileInsertResult.first->second.getError()); 208 return FileEntryRef(*SeenFileInsertResult.first); 209 } 210 211 // We've not seen this before. Fill it in. 212 ++NumFileCacheMisses; 213 auto *NamedFileEnt = &*SeenFileInsertResult.first; 214 assert(!NamedFileEnt->second && "should be newly-created"); 215 216 // Get the null-terminated file name as stored as the key of the 217 // SeenFileEntries map. 218 StringRef InterndFileName = NamedFileEnt->first(); 219 220 // Look up the directory for the file. When looking up something like 221 // sys/foo.h we'll discover all of the search directories that have a 'sys' 222 // subdirectory. This will let us avoid having to waste time on known-to-fail 223 // searches when we go to find sys/bar.h, because all the search directories 224 // without a 'sys' subdir will get a cached failure result. 225 auto DirInfoOrErr = getDirectoryFromFile(*this, Filename, CacheFailure); 226 if (!DirInfoOrErr) { // Directory doesn't exist, file can't exist. 227 std::error_code Err = errorToErrorCode(DirInfoOrErr.takeError()); 228 if (CacheFailure) 229 NamedFileEnt->second = Err; 230 else 231 SeenFileEntries.erase(Filename); 232 233 return llvm::errorCodeToError(Err); 234 } 235 DirectoryEntryRef DirInfo = *DirInfoOrErr; 236 237 // FIXME: Use the directory info to prune this, before doing the stat syscall. 238 // FIXME: This will reduce the # syscalls. 239 240 // Check to see if the file exists. 241 std::unique_ptr<llvm::vfs::File> F; 242 llvm::vfs::Status Status; 243 auto statError = getStatValue(InterndFileName, Status, true, 244 openFile ? &F : nullptr); 245 if (statError) { 246 // There's no real file at the given path. 247 if (CacheFailure) 248 NamedFileEnt->second = statError; 249 else 250 SeenFileEntries.erase(Filename); 251 252 return llvm::errorCodeToError(statError); 253 } 254 255 assert((openFile || !F) && "undesired open file"); 256 257 // It exists. See if we have already opened a file with the same inode. 258 // This occurs when one dir is symlinked to another, for example. 259 FileEntry *&UFE = UniqueRealFiles[Status.getUniqueID()]; 260 bool ReusingEntry = UFE != nullptr; 261 if (!UFE) 262 UFE = new (FilesAlloc.Allocate()) FileEntry(); 263 264 if (!Status.ExposesExternalVFSPath || Status.getName() == Filename) { 265 // Use the requested name. Set the FileEntry. 266 NamedFileEnt->second = FileEntryRef::MapValue(*UFE, DirInfo); 267 } else { 268 // Name mismatch. We need a redirect. First grab the actual entry we want 269 // to return. 270 // 271 // This redirection logic intentionally leaks the external name of a 272 // redirected file that uses 'use-external-name' in \a 273 // vfs::RedirectionFileSystem. This allows clang to report the external 274 // name to users (in diagnostics) and to tools that don't have access to 275 // the VFS (in debug info and dependency '.d' files). 276 // 277 // FIXME: This is pretty complex and has some very complicated interactions 278 // with the rest of clang. It's also inconsistent with how "real" 279 // filesystems behave and confuses parts of clang expect to see the 280 // name-as-accessed on the \a FileEntryRef. 281 // 282 // A potential plan to remove this is as follows - 283 // - Update callers such as `HeaderSearch::findUsableModuleForHeader()` 284 // to explicitly use the `getNameAsRequested()` rather than just using 285 // `getName()`. 286 // - Add a `FileManager::getExternalPath` API for explicitly getting the 287 // remapped external filename when there is one available. Adopt it in 288 // callers like diagnostics/deps reporting instead of calling 289 // `getName()` directly. 290 // - Switch the meaning of `FileEntryRef::getName()` to get the requested 291 // name, not the external name. Once that sticks, revert callers that 292 // want the requested name back to calling `getName()`. 293 // - Update the VFS to always return the requested name. This could also 294 // return the external name, or just have an API to request it 295 // lazily. The latter has the benefit of making accesses of the 296 // external path easily tracked, but may also require extra work than 297 // just returning up front. 298 // - (Optionally) Add an API to VFS to get the external filename lazily 299 // and update `FileManager::getExternalPath()` to use it instead. This 300 // has the benefit of making such accesses easily tracked, though isn't 301 // necessarily required (and could cause extra work than just adding to 302 // eg. `vfs::Status` up front). 303 auto &Redirection = 304 *SeenFileEntries 305 .insert({Status.getName(), FileEntryRef::MapValue(*UFE, DirInfo)}) 306 .first; 307 assert(Redirection.second->V.is<FileEntry *>() && 308 "filename redirected to a non-canonical filename?"); 309 assert(Redirection.second->V.get<FileEntry *>() == UFE && 310 "filename from getStatValue() refers to wrong file"); 311 312 // Cache the redirection in the previously-inserted entry, still available 313 // in the tentative return value. 314 NamedFileEnt->second = FileEntryRef::MapValue(Redirection, DirInfo); 315 } 316 317 FileEntryRef ReturnedRef(*NamedFileEnt); 318 if (ReusingEntry) { // Already have an entry with this inode, return it. 319 return ReturnedRef; 320 } 321 322 // Otherwise, we don't have this file yet, add it. 323 UFE->Size = Status.getSize(); 324 UFE->ModTime = llvm::sys::toTimeT(Status.getLastModificationTime()); 325 UFE->Dir = &DirInfo.getDirEntry(); 326 UFE->UID = NextFileUID++; 327 UFE->UniqueID = Status.getUniqueID(); 328 UFE->IsNamedPipe = Status.getType() == llvm::sys::fs::file_type::fifo_file; 329 UFE->File = std::move(F); 330 331 if (UFE->File) { 332 if (auto PathName = UFE->File->getName()) 333 fillRealPathName(UFE, *PathName); 334 } else if (!openFile) { 335 // We should still fill the path even if we aren't opening the file. 336 fillRealPathName(UFE, InterndFileName); 337 } 338 return ReturnedRef; 339 } 340 341 llvm::Expected<FileEntryRef> FileManager::getSTDIN() { 342 // Only read stdin once. 343 if (STDIN) 344 return *STDIN; 345 346 std::unique_ptr<llvm::MemoryBuffer> Content; 347 if (auto ContentOrError = llvm::MemoryBuffer::getSTDIN()) 348 Content = std::move(*ContentOrError); 349 else 350 return llvm::errorCodeToError(ContentOrError.getError()); 351 352 STDIN = getVirtualFileRef(Content->getBufferIdentifier(), 353 Content->getBufferSize(), 0); 354 FileEntry &FE = const_cast<FileEntry &>(STDIN->getFileEntry()); 355 FE.Content = std::move(Content); 356 FE.IsNamedPipe = true; 357 return *STDIN; 358 } 359 360 void FileManager::trackVFSUsage(bool Active) { 361 FS->visit([Active](llvm::vfs::FileSystem &FileSys) { 362 if (auto *RFS = dyn_cast<llvm::vfs::RedirectingFileSystem>(&FileSys)) 363 RFS->setUsageTrackingActive(Active); 364 }); 365 } 366 367 const FileEntry *FileManager::getVirtualFile(StringRef Filename, off_t Size, 368 time_t ModificationTime) { 369 return &getVirtualFileRef(Filename, Size, ModificationTime).getFileEntry(); 370 } 371 372 FileEntryRef FileManager::getVirtualFileRef(StringRef Filename, off_t Size, 373 time_t ModificationTime) { 374 ++NumFileLookups; 375 376 // See if there is already an entry in the map for an existing file. 377 auto &NamedFileEnt = *SeenFileEntries.insert( 378 {Filename, std::errc::no_such_file_or_directory}).first; 379 if (NamedFileEnt.second) { 380 FileEntryRef::MapValue Value = *NamedFileEnt.second; 381 if (LLVM_LIKELY(Value.V.is<FileEntry *>())) 382 return FileEntryRef(NamedFileEnt); 383 return FileEntryRef(*Value.V.get<const FileEntryRef::MapEntry *>()); 384 } 385 386 // We've not seen this before, or the file is cached as non-existent. 387 ++NumFileCacheMisses; 388 addAncestorsAsVirtualDirs(Filename); 389 FileEntry *UFE = nullptr; 390 391 // Now that all ancestors of Filename are in the cache, the 392 // following call is guaranteed to find the DirectoryEntry from the 393 // cache. A virtual file can also have an empty filename, that could come 394 // from a source location preprocessor directive with an empty filename as 395 // an example, so we need to pretend it has a name to ensure a valid directory 396 // entry can be returned. 397 auto DirInfo = expectedToOptional(getDirectoryFromFile( 398 *this, Filename.empty() ? "." : Filename, /*CacheFailure=*/true)); 399 assert(DirInfo && 400 "The directory of a virtual file should already be in the cache."); 401 402 // Check to see if the file exists. If so, drop the virtual file 403 llvm::vfs::Status Status; 404 const char *InterndFileName = NamedFileEnt.first().data(); 405 if (!getStatValue(InterndFileName, Status, true, nullptr)) { 406 Status = llvm::vfs::Status( 407 Status.getName(), Status.getUniqueID(), 408 llvm::sys::toTimePoint(ModificationTime), 409 Status.getUser(), Status.getGroup(), Size, 410 Status.getType(), Status.getPermissions()); 411 412 auto &RealFE = UniqueRealFiles[Status.getUniqueID()]; 413 if (RealFE) { 414 // If we had already opened this file, close it now so we don't 415 // leak the descriptor. We're not going to use the file 416 // descriptor anyway, since this is a virtual file. 417 if (RealFE->File) 418 RealFE->closeFile(); 419 // If we already have an entry with this inode, return it. 420 // 421 // FIXME: Surely this should add a reference by the new name, and return 422 // it instead... 423 NamedFileEnt.second = FileEntryRef::MapValue(*RealFE, *DirInfo); 424 return FileEntryRef(NamedFileEnt); 425 } 426 // File exists, but no entry - create it. 427 RealFE = new (FilesAlloc.Allocate()) FileEntry(); 428 RealFE->UniqueID = Status.getUniqueID(); 429 RealFE->IsNamedPipe = 430 Status.getType() == llvm::sys::fs::file_type::fifo_file; 431 fillRealPathName(RealFE, Status.getName()); 432 433 UFE = RealFE; 434 } else { 435 // File does not exist, create a virtual entry. 436 UFE = new (FilesAlloc.Allocate()) FileEntry(); 437 VirtualFileEntries.push_back(UFE); 438 } 439 440 NamedFileEnt.second = FileEntryRef::MapValue(*UFE, *DirInfo); 441 UFE->Size = Size; 442 UFE->ModTime = ModificationTime; 443 UFE->Dir = &DirInfo->getDirEntry(); 444 UFE->UID = NextFileUID++; 445 UFE->File.reset(); 446 return FileEntryRef(NamedFileEnt); 447 } 448 449 OptionalFileEntryRef FileManager::getBypassFile(FileEntryRef VF) { 450 // Stat of the file and return nullptr if it doesn't exist. 451 llvm::vfs::Status Status; 452 if (getStatValue(VF.getName(), Status, /*isFile=*/true, /*F=*/nullptr)) 453 return std::nullopt; 454 455 if (!SeenBypassFileEntries) 456 SeenBypassFileEntries = std::make_unique< 457 llvm::StringMap<llvm::ErrorOr<FileEntryRef::MapValue>>>(); 458 459 // If we've already bypassed just use the existing one. 460 auto Insertion = SeenBypassFileEntries->insert( 461 {VF.getName(), std::errc::no_such_file_or_directory}); 462 if (!Insertion.second) 463 return FileEntryRef(*Insertion.first); 464 465 // Fill in the new entry from the stat. 466 FileEntry *BFE = new (FilesAlloc.Allocate()) FileEntry(); 467 BypassFileEntries.push_back(BFE); 468 Insertion.first->second = FileEntryRef::MapValue(*BFE, VF.getDir()); 469 BFE->Size = Status.getSize(); 470 BFE->Dir = VF.getFileEntry().Dir; 471 BFE->ModTime = llvm::sys::toTimeT(Status.getLastModificationTime()); 472 BFE->UID = NextFileUID++; 473 474 // Save the entry in the bypass table and return. 475 return FileEntryRef(*Insertion.first); 476 } 477 478 bool FileManager::FixupRelativePath(SmallVectorImpl<char> &path) const { 479 StringRef pathRef(path.data(), path.size()); 480 481 if (FileSystemOpts.WorkingDir.empty() 482 || llvm::sys::path::is_absolute(pathRef)) 483 return false; 484 485 SmallString<128> NewPath(FileSystemOpts.WorkingDir); 486 llvm::sys::path::append(NewPath, pathRef); 487 path = NewPath; 488 return true; 489 } 490 491 bool FileManager::makeAbsolutePath(SmallVectorImpl<char> &Path) const { 492 bool Changed = FixupRelativePath(Path); 493 494 if (!llvm::sys::path::is_absolute(StringRef(Path.data(), Path.size()))) { 495 FS->makeAbsolute(Path); 496 Changed = true; 497 } 498 499 return Changed; 500 } 501 502 void FileManager::fillRealPathName(FileEntry *UFE, llvm::StringRef FileName) { 503 llvm::SmallString<128> AbsPath(FileName); 504 // This is not the same as `VFS::getRealPath()`, which resolves symlinks 505 // but can be very expensive on real file systems. 506 // FIXME: the semantic of RealPathName is unclear, and the name might be 507 // misleading. We need to clean up the interface here. 508 makeAbsolutePath(AbsPath); 509 llvm::sys::path::remove_dots(AbsPath, /*remove_dot_dot=*/true); 510 UFE->RealPathName = std::string(AbsPath); 511 } 512 513 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> 514 FileManager::getBufferForFile(FileEntryRef FE, bool isVolatile, 515 bool RequiresNullTerminator) { 516 const FileEntry *Entry = &FE.getFileEntry(); 517 // If the content is living on the file entry, return a reference to it. 518 if (Entry->Content) 519 return llvm::MemoryBuffer::getMemBuffer(Entry->Content->getMemBufferRef()); 520 521 uint64_t FileSize = Entry->getSize(); 522 // If there's a high enough chance that the file have changed since we 523 // got its size, force a stat before opening it. 524 if (isVolatile || Entry->isNamedPipe()) 525 FileSize = -1; 526 527 StringRef Filename = FE.getName(); 528 // If the file is already open, use the open file descriptor. 529 if (Entry->File) { 530 auto Result = Entry->File->getBuffer(Filename, FileSize, 531 RequiresNullTerminator, isVolatile); 532 Entry->closeFile(); 533 return Result; 534 } 535 536 // Otherwise, open the file. 537 return getBufferForFileImpl(Filename, FileSize, isVolatile, 538 RequiresNullTerminator); 539 } 540 541 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> 542 FileManager::getBufferForFileImpl(StringRef Filename, int64_t FileSize, 543 bool isVolatile, 544 bool RequiresNullTerminator) const { 545 if (FileSystemOpts.WorkingDir.empty()) 546 return FS->getBufferForFile(Filename, FileSize, RequiresNullTerminator, 547 isVolatile); 548 549 SmallString<128> FilePath(Filename); 550 FixupRelativePath(FilePath); 551 return FS->getBufferForFile(FilePath, FileSize, RequiresNullTerminator, 552 isVolatile); 553 } 554 555 /// getStatValue - Get the 'stat' information for the specified path, 556 /// using the cache to accelerate it if possible. This returns true 557 /// if the path points to a virtual file or does not exist, or returns 558 /// false if it's an existent real file. If FileDescriptor is NULL, 559 /// do directory look-up instead of file look-up. 560 std::error_code 561 FileManager::getStatValue(StringRef Path, llvm::vfs::Status &Status, 562 bool isFile, std::unique_ptr<llvm::vfs::File> *F) { 563 // FIXME: FileSystemOpts shouldn't be passed in here, all paths should be 564 // absolute! 565 if (FileSystemOpts.WorkingDir.empty()) 566 return FileSystemStatCache::get(Path, Status, isFile, F, 567 StatCache.get(), *FS); 568 569 SmallString<128> FilePath(Path); 570 FixupRelativePath(FilePath); 571 572 return FileSystemStatCache::get(FilePath.c_str(), Status, isFile, F, 573 StatCache.get(), *FS); 574 } 575 576 std::error_code 577 FileManager::getNoncachedStatValue(StringRef Path, 578 llvm::vfs::Status &Result) { 579 SmallString<128> FilePath(Path); 580 FixupRelativePath(FilePath); 581 582 llvm::ErrorOr<llvm::vfs::Status> S = FS->status(FilePath.c_str()); 583 if (!S) 584 return S.getError(); 585 Result = *S; 586 return std::error_code(); 587 } 588 589 void FileManager::GetUniqueIDMapping( 590 SmallVectorImpl<OptionalFileEntryRef> &UIDToFiles) const { 591 UIDToFiles.clear(); 592 UIDToFiles.resize(NextFileUID); 593 594 for (const auto &Entry : SeenFileEntries) { 595 // Only return files that exist and are not redirected. 596 if (!Entry.getValue() || !Entry.getValue()->V.is<FileEntry *>()) 597 continue; 598 FileEntryRef FE(Entry); 599 // Add this file if it's the first one with the UID, or if its name is 600 // better than the existing one. 601 OptionalFileEntryRef &ExistingFE = UIDToFiles[FE.getUID()]; 602 if (!ExistingFE || FE.getName() < ExistingFE->getName()) 603 ExistingFE = FE; 604 } 605 } 606 607 StringRef FileManager::getCanonicalName(DirectoryEntryRef Dir) { 608 return getCanonicalName(Dir, Dir.getName()); 609 } 610 611 StringRef FileManager::getCanonicalName(FileEntryRef File) { 612 return getCanonicalName(File, File.getName()); 613 } 614 615 StringRef FileManager::getCanonicalName(const void *Entry, StringRef Name) { 616 llvm::DenseMap<const void *, llvm::StringRef>::iterator Known = 617 CanonicalNames.find(Entry); 618 if (Known != CanonicalNames.end()) 619 return Known->second; 620 621 // Name comes from FileEntry/DirectoryEntry::getName(), so it is safe to 622 // store it in the DenseMap below. 623 StringRef CanonicalName(Name); 624 625 SmallString<256> AbsPathBuf; 626 SmallString<256> RealPathBuf; 627 if (!FS->getRealPath(Name, RealPathBuf)) { 628 if (is_style_windows(llvm::sys::path::Style::native)) { 629 // For Windows paths, only use the real path if it doesn't resolve 630 // a substitute drive, as those are used to avoid MAX_PATH issues. 631 AbsPathBuf = Name; 632 if (!FS->makeAbsolute(AbsPathBuf)) { 633 if (llvm::sys::path::root_name(RealPathBuf) == 634 llvm::sys::path::root_name(AbsPathBuf)) { 635 CanonicalName = RealPathBuf.str().copy(CanonicalNameStorage); 636 } else { 637 // Fallback to using the absolute path. 638 // Simplifying /../ is semantically valid on Windows even in the 639 // presence of symbolic links. 640 llvm::sys::path::remove_dots(AbsPathBuf, /*remove_dot_dot=*/true); 641 CanonicalName = AbsPathBuf.str().copy(CanonicalNameStorage); 642 } 643 } 644 } else { 645 CanonicalName = RealPathBuf.str().copy(CanonicalNameStorage); 646 } 647 } 648 649 CanonicalNames.insert({Entry, CanonicalName}); 650 return CanonicalName; 651 } 652 653 void FileManager::AddStats(const FileManager &Other) { 654 assert(&Other != this && "Collecting stats into the same FileManager"); 655 NumDirLookups += Other.NumDirLookups; 656 NumFileLookups += Other.NumFileLookups; 657 NumDirCacheMisses += Other.NumDirCacheMisses; 658 NumFileCacheMisses += Other.NumFileCacheMisses; 659 } 660 661 void FileManager::PrintStats() const { 662 llvm::errs() << "\n*** File Manager Stats:\n"; 663 llvm::errs() << UniqueRealFiles.size() << " real files found, " 664 << UniqueRealDirs.size() << " real dirs found.\n"; 665 llvm::errs() << VirtualFileEntries.size() << " virtual files found, " 666 << VirtualDirectoryEntries.size() << " virtual dirs found.\n"; 667 llvm::errs() << NumDirLookups << " dir lookups, " 668 << NumDirCacheMisses << " dir cache misses.\n"; 669 llvm::errs() << NumFileLookups << " file lookups, " 670 << NumFileCacheMisses << " file cache misses.\n"; 671 672 //llvm::errs() << PagesMapped << BytesOfPagesMapped << FSLookups; 673 } 674