File: | clang/lib/Basic/FileManager.cpp |
Warning: | line 288, column 5 Value stored to 'NamedFileEnt' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 <string> |
35 | #include <utility> |
36 | |
37 | using namespace clang; |
38 | |
39 | #define DEBUG_TYPE"file-search" "file-search" |
40 | |
41 | ALWAYS_ENABLED_STATISTIC(NumDirLookups, "Number of directory lookups.")static llvm::TrackingStatistic NumDirLookups = {"file-search" , "NumDirLookups", "Number of directory lookups."}; |
42 | ALWAYS_ENABLED_STATISTIC(NumFileLookups, "Number of file lookups.")static llvm::TrackingStatistic NumFileLookups = {"file-search" , "NumFileLookups", "Number of file lookups."}; |
43 | ALWAYS_ENABLED_STATISTIC(NumDirCacheMisses,static llvm::TrackingStatistic NumDirCacheMisses = {"file-search" , "NumDirCacheMisses", "Number of directory cache misses."} |
44 | "Number of directory cache misses.")static llvm::TrackingStatistic NumDirCacheMisses = {"file-search" , "NumDirCacheMisses", "Number of directory cache misses."}; |
45 | ALWAYS_ENABLED_STATISTIC(NumFileCacheMisses, "Number of file cache misses.")static llvm::TrackingStatistic NumFileCacheMisses = {"file-search" , "NumFileCacheMisses", "Number of file cache misses."}; |
46 | |
47 | //===----------------------------------------------------------------------===// |
48 | // Common logic. |
49 | //===----------------------------------------------------------------------===// |
50 | |
51 | FileManager::FileManager(const FileSystemOptions &FSO, |
52 | IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) |
53 | : FS(std::move(FS)), FileSystemOpts(FSO), SeenDirEntries(64), |
54 | SeenFileEntries(64), NextFileUID(0) { |
55 | // If the caller doesn't provide a virtual file system, just grab the real |
56 | // file system. |
57 | if (!this->FS) |
58 | this->FS = llvm::vfs::getRealFileSystem(); |
59 | } |
60 | |
61 | FileManager::~FileManager() = default; |
62 | |
63 | void FileManager::setStatCache(std::unique_ptr<FileSystemStatCache> statCache) { |
64 | assert(statCache && "No stat cache provided?")((statCache && "No stat cache provided?") ? static_cast <void> (0) : __assert_fail ("statCache && \"No stat cache provided?\"" , "/build/llvm-toolchain-snapshot-12~++20201026111116+d3205bbca3e/clang/lib/Basic/FileManager.cpp" , 64, __PRETTY_FUNCTION__)); |
65 | StatCache = std::move(statCache); |
66 | } |
67 | |
68 | void FileManager::clearStatCache() { StatCache.reset(); } |
69 | |
70 | /// Retrieve the directory that the given file name resides in. |
71 | /// Filename can point to either a real file or a virtual file. |
72 | static llvm::ErrorOr<const DirectoryEntry *> |
73 | getDirectoryFromFile(FileManager &FileMgr, StringRef Filename, |
74 | bool CacheFailure) { |
75 | if (Filename.empty()) |
76 | return std::errc::no_such_file_or_directory; |
77 | |
78 | if (llvm::sys::path::is_separator(Filename[Filename.size() - 1])) |
79 | return std::errc::is_a_directory; |
80 | |
81 | StringRef DirName = llvm::sys::path::parent_path(Filename); |
82 | // Use the current directory if file has no path component. |
83 | if (DirName.empty()) |
84 | DirName = "."; |
85 | |
86 | return FileMgr.getDirectory(DirName, CacheFailure); |
87 | } |
88 | |
89 | /// Add all ancestors of the given path (pointing to either a file or |
90 | /// a directory) as virtual directories. |
91 | void FileManager::addAncestorsAsVirtualDirs(StringRef Path) { |
92 | StringRef DirName = llvm::sys::path::parent_path(Path); |
93 | if (DirName.empty()) |
94 | DirName = "."; |
95 | |
96 | auto &NamedDirEnt = *SeenDirEntries.insert( |
97 | {DirName, std::errc::no_such_file_or_directory}).first; |
98 | |
99 | // When caching a virtual directory, we always cache its ancestors |
100 | // at the same time. Therefore, if DirName is already in the cache, |
101 | // we don't need to recurse as its ancestors must also already be in |
102 | // the cache (or it's a known non-virtual directory). |
103 | if (NamedDirEnt.second) |
104 | return; |
105 | |
106 | // Add the virtual directory to the cache. |
107 | auto UDE = std::make_unique<DirectoryEntry>(); |
108 | UDE->Name = NamedDirEnt.first(); |
109 | NamedDirEnt.second = *UDE.get(); |
110 | VirtualDirectoryEntries.push_back(std::move(UDE)); |
111 | |
112 | // Recursively add the other ancestors. |
113 | addAncestorsAsVirtualDirs(DirName); |
114 | } |
115 | |
116 | llvm::Expected<DirectoryEntryRef> |
117 | FileManager::getDirectoryRef(StringRef DirName, bool CacheFailure) { |
118 | // stat doesn't like trailing separators except for root directory. |
119 | // At least, on Win32 MSVCRT, stat() cannot strip trailing '/'. |
120 | // (though it can strip '\\') |
121 | if (DirName.size() > 1 && |
122 | DirName != llvm::sys::path::root_path(DirName) && |
123 | llvm::sys::path::is_separator(DirName.back())) |
124 | DirName = DirName.substr(0, DirName.size()-1); |
125 | #ifdef _WIN32 |
126 | // Fixing a problem with "clang C:test.c" on Windows. |
127 | // Stat("C:") does not recognize "C:" as a valid directory |
128 | std::string DirNameStr; |
129 | if (DirName.size() > 1 && DirName.back() == ':' && |
130 | DirName.equals_lower(llvm::sys::path::root_name(DirName))) { |
131 | DirNameStr = DirName.str() + '.'; |
132 | DirName = DirNameStr; |
133 | } |
134 | #endif |
135 | |
136 | ++NumDirLookups; |
137 | |
138 | // See if there was already an entry in the map. Note that the map |
139 | // contains both virtual and real directories. |
140 | auto SeenDirInsertResult = |
141 | SeenDirEntries.insert({DirName, std::errc::no_such_file_or_directory}); |
142 | if (!SeenDirInsertResult.second) { |
143 | if (SeenDirInsertResult.first->second) |
144 | return DirectoryEntryRef(&*SeenDirInsertResult.first); |
145 | return llvm::errorCodeToError(SeenDirInsertResult.first->second.getError()); |
146 | } |
147 | |
148 | // We've not seen this before. Fill it in. |
149 | ++NumDirCacheMisses; |
150 | auto &NamedDirEnt = *SeenDirInsertResult.first; |
151 | assert(!NamedDirEnt.second && "should be newly-created")((!NamedDirEnt.second && "should be newly-created") ? static_cast<void> (0) : __assert_fail ("!NamedDirEnt.second && \"should be newly-created\"" , "/build/llvm-toolchain-snapshot-12~++20201026111116+d3205bbca3e/clang/lib/Basic/FileManager.cpp" , 151, __PRETTY_FUNCTION__)); |
152 | |
153 | // Get the null-terminated directory name as stored as the key of the |
154 | // SeenDirEntries map. |
155 | StringRef InterndDirName = NamedDirEnt.first(); |
156 | |
157 | // Check to see if the directory exists. |
158 | llvm::vfs::Status Status; |
159 | auto statError = getStatValue(InterndDirName, Status, false, |
160 | nullptr /*directory lookup*/); |
161 | if (statError) { |
162 | // There's no real directory at the given path. |
163 | if (CacheFailure) |
164 | NamedDirEnt.second = statError; |
165 | else |
166 | SeenDirEntries.erase(DirName); |
167 | return llvm::errorCodeToError(statError); |
168 | } |
169 | |
170 | // It exists. See if we have already opened a directory with the |
171 | // same inode (this occurs on Unix-like systems when one dir is |
172 | // symlinked to another, for example) or the same path (on |
173 | // Windows). |
174 | DirectoryEntry &UDE = UniqueRealDirs[Status.getUniqueID()]; |
175 | |
176 | NamedDirEnt.second = UDE; |
177 | if (UDE.getName().empty()) { |
178 | // We don't have this directory yet, add it. We use the string |
179 | // key from the SeenDirEntries map as the string. |
180 | UDE.Name = InterndDirName; |
181 | } |
182 | |
183 | return DirectoryEntryRef(&NamedDirEnt); |
184 | } |
185 | |
186 | llvm::ErrorOr<const DirectoryEntry *> |
187 | FileManager::getDirectory(StringRef DirName, bool CacheFailure) { |
188 | auto Result = getDirectoryRef(DirName, CacheFailure); |
189 | if (Result) |
190 | return &Result->getDirEntry(); |
191 | return llvm::errorToErrorCode(Result.takeError()); |
192 | } |
193 | |
194 | llvm::ErrorOr<const FileEntry *> |
195 | FileManager::getFile(StringRef Filename, bool openFile, bool CacheFailure) { |
196 | auto Result = getFileRef(Filename, openFile, CacheFailure); |
197 | if (Result) |
198 | return &Result->getFileEntry(); |
199 | return llvm::errorToErrorCode(Result.takeError()); |
200 | } |
201 | |
202 | llvm::Expected<FileEntryRef> |
203 | FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) { |
204 | ++NumFileLookups; |
205 | |
206 | // See if there is already an entry in the map. |
207 | auto SeenFileInsertResult = |
208 | SeenFileEntries.insert({Filename, std::errc::no_such_file_or_directory}); |
209 | if (!SeenFileInsertResult.second) { |
210 | if (!SeenFileInsertResult.first->second) |
211 | return llvm::errorCodeToError( |
212 | SeenFileInsertResult.first->second.getError()); |
213 | // Construct and return and FileEntryRef, unless it's a redirect to another |
214 | // filename. |
215 | SeenFileEntryOrRedirect Value = *SeenFileInsertResult.first->second; |
216 | FileEntry *FE; |
217 | if (LLVM_LIKELY(FE = Value.dyn_cast<FileEntry *>())__builtin_expect((bool)(FE = Value.dyn_cast<FileEntry *> ()), true)) |
218 | return FileEntryRef(SeenFileInsertResult.first->first(), *FE); |
219 | return getFileRef(*Value.get<const StringRef *>(), openFile, CacheFailure); |
220 | } |
221 | |
222 | // We've not seen this before. Fill it in. |
223 | ++NumFileCacheMisses; |
224 | auto *NamedFileEnt = &*SeenFileInsertResult.first; |
225 | assert(!NamedFileEnt->second && "should be newly-created")((!NamedFileEnt->second && "should be newly-created" ) ? static_cast<void> (0) : __assert_fail ("!NamedFileEnt->second && \"should be newly-created\"" , "/build/llvm-toolchain-snapshot-12~++20201026111116+d3205bbca3e/clang/lib/Basic/FileManager.cpp" , 225, __PRETTY_FUNCTION__)); |
226 | |
227 | // Get the null-terminated file name as stored as the key of the |
228 | // SeenFileEntries map. |
229 | StringRef InterndFileName = NamedFileEnt->first(); |
230 | |
231 | // Look up the directory for the file. When looking up something like |
232 | // sys/foo.h we'll discover all of the search directories that have a 'sys' |
233 | // subdirectory. This will let us avoid having to waste time on known-to-fail |
234 | // searches when we go to find sys/bar.h, because all the search directories |
235 | // without a 'sys' subdir will get a cached failure result. |
236 | auto DirInfoOrErr = getDirectoryFromFile(*this, Filename, CacheFailure); |
237 | if (!DirInfoOrErr) { // Directory doesn't exist, file can't exist. |
238 | if (CacheFailure) |
239 | NamedFileEnt->second = DirInfoOrErr.getError(); |
240 | else |
241 | SeenFileEntries.erase(Filename); |
242 | |
243 | return llvm::errorCodeToError(DirInfoOrErr.getError()); |
244 | } |
245 | const DirectoryEntry *DirInfo = *DirInfoOrErr; |
246 | |
247 | // FIXME: Use the directory info to prune this, before doing the stat syscall. |
248 | // FIXME: This will reduce the # syscalls. |
249 | |
250 | // Check to see if the file exists. |
251 | std::unique_ptr<llvm::vfs::File> F; |
252 | llvm::vfs::Status Status; |
253 | auto statError = getStatValue(InterndFileName, Status, true, |
254 | openFile ? &F : nullptr); |
255 | if (statError) { |
256 | // There's no real file at the given path. |
257 | if (CacheFailure) |
258 | NamedFileEnt->second = statError; |
259 | else |
260 | SeenFileEntries.erase(Filename); |
261 | |
262 | return llvm::errorCodeToError(statError); |
263 | } |
264 | |
265 | assert((openFile || !F) && "undesired open file")(((openFile || !F) && "undesired open file") ? static_cast <void> (0) : __assert_fail ("(openFile || !F) && \"undesired open file\"" , "/build/llvm-toolchain-snapshot-12~++20201026111116+d3205bbca3e/clang/lib/Basic/FileManager.cpp" , 265, __PRETTY_FUNCTION__)); |
266 | |
267 | // It exists. See if we have already opened a file with the same inode. |
268 | // This occurs when one dir is symlinked to another, for example. |
269 | FileEntry &UFE = UniqueRealFiles[Status.getUniqueID()]; |
270 | |
271 | NamedFileEnt->second = &UFE; |
272 | |
273 | // If the name returned by getStatValue is different than Filename, re-intern |
274 | // the name. |
275 | if (Status.getName() != Filename) { |
276 | auto &NewNamedFileEnt = |
277 | *SeenFileEntries.insert({Status.getName(), &UFE}).first; |
278 | assert((*NewNamedFileEnt.second).get<FileEntry *>() == &UFE &&(((*NewNamedFileEnt.second).get<FileEntry *>() == & UFE && "filename from getStatValue() refers to wrong file" ) ? static_cast<void> (0) : __assert_fail ("(*NewNamedFileEnt.second).get<FileEntry *>() == &UFE && \"filename from getStatValue() refers to wrong file\"" , "/build/llvm-toolchain-snapshot-12~++20201026111116+d3205bbca3e/clang/lib/Basic/FileManager.cpp" , 279, __PRETTY_FUNCTION__)) |
279 | "filename from getStatValue() refers to wrong file")(((*NewNamedFileEnt.second).get<FileEntry *>() == & UFE && "filename from getStatValue() refers to wrong file" ) ? static_cast<void> (0) : __assert_fail ("(*NewNamedFileEnt.second).get<FileEntry *>() == &UFE && \"filename from getStatValue() refers to wrong file\"" , "/build/llvm-toolchain-snapshot-12~++20201026111116+d3205bbca3e/clang/lib/Basic/FileManager.cpp" , 279, __PRETTY_FUNCTION__)); |
280 | InterndFileName = NewNamedFileEnt.first().data(); |
281 | // In addition to re-interning the name, construct a redirecting seen file |
282 | // entry, that will point to the name the filesystem actually wants to use. |
283 | StringRef *Redirect = new (CanonicalNameStorage) StringRef(InterndFileName); |
284 | auto SeenFileInsertResultIt = SeenFileEntries.find(Filename); |
285 | assert(SeenFileInsertResultIt != SeenFileEntries.end() &&((SeenFileInsertResultIt != SeenFileEntries.end() && "unexpected SeenFileEntries cache miss" ) ? static_cast<void> (0) : __assert_fail ("SeenFileInsertResultIt != SeenFileEntries.end() && \"unexpected SeenFileEntries cache miss\"" , "/build/llvm-toolchain-snapshot-12~++20201026111116+d3205bbca3e/clang/lib/Basic/FileManager.cpp" , 286, __PRETTY_FUNCTION__)) |
286 | "unexpected SeenFileEntries cache miss")((SeenFileInsertResultIt != SeenFileEntries.end() && "unexpected SeenFileEntries cache miss" ) ? static_cast<void> (0) : __assert_fail ("SeenFileInsertResultIt != SeenFileEntries.end() && \"unexpected SeenFileEntries cache miss\"" , "/build/llvm-toolchain-snapshot-12~++20201026111116+d3205bbca3e/clang/lib/Basic/FileManager.cpp" , 286, __PRETTY_FUNCTION__)); |
287 | SeenFileInsertResultIt->second = Redirect; |
288 | NamedFileEnt = &*SeenFileInsertResultIt; |
Value stored to 'NamedFileEnt' is never read | |
289 | } |
290 | |
291 | if (UFE.isValid()) { // Already have an entry with this inode, return it. |
292 | |
293 | // FIXME: this hack ensures that if we look up a file by a virtual path in |
294 | // the VFS that the getDir() will have the virtual path, even if we found |
295 | // the file by a 'real' path first. This is required in order to find a |
296 | // module's structure when its headers/module map are mapped in the VFS. |
297 | // We should remove this as soon as we can properly support a file having |
298 | // multiple names. |
299 | if (DirInfo != UFE.Dir && Status.IsVFSMapped) |
300 | UFE.Dir = DirInfo; |
301 | |
302 | // Always update the name to use the last name by which a file was accessed. |
303 | // FIXME: Neither this nor always using the first name is correct; we want |
304 | // to switch towards a design where we return a FileName object that |
305 | // encapsulates both the name by which the file was accessed and the |
306 | // corresponding FileEntry. |
307 | // FIXME: The Name should be removed from FileEntry once all clients |
308 | // adopt FileEntryRef. |
309 | UFE.Name = InterndFileName; |
310 | |
311 | return FileEntryRef(InterndFileName, UFE); |
312 | } |
313 | |
314 | // Otherwise, we don't have this file yet, add it. |
315 | UFE.Name = InterndFileName; |
316 | UFE.Size = Status.getSize(); |
317 | UFE.ModTime = llvm::sys::toTimeT(Status.getLastModificationTime()); |
318 | UFE.Dir = DirInfo; |
319 | UFE.UID = NextFileUID++; |
320 | UFE.UniqueID = Status.getUniqueID(); |
321 | UFE.IsNamedPipe = Status.getType() == llvm::sys::fs::file_type::fifo_file; |
322 | UFE.File = std::move(F); |
323 | UFE.IsValid = true; |
324 | |
325 | if (UFE.File) { |
326 | if (auto PathName = UFE.File->getName()) |
327 | fillRealPathName(&UFE, *PathName); |
328 | } else if (!openFile) { |
329 | // We should still fill the path even if we aren't opening the file. |
330 | fillRealPathName(&UFE, InterndFileName); |
331 | } |
332 | return FileEntryRef(InterndFileName, UFE); |
333 | } |
334 | |
335 | const FileEntry * |
336 | FileManager::getVirtualFile(StringRef Filename, off_t Size, |
337 | time_t ModificationTime) { |
338 | ++NumFileLookups; |
339 | |
340 | // See if there is already an entry in the map for an existing file. |
341 | auto &NamedFileEnt = *SeenFileEntries.insert( |
342 | {Filename, std::errc::no_such_file_or_directory}).first; |
343 | if (NamedFileEnt.second) { |
344 | SeenFileEntryOrRedirect Value = *NamedFileEnt.second; |
345 | FileEntry *FE; |
346 | if (LLVM_LIKELY(FE = Value.dyn_cast<FileEntry *>())__builtin_expect((bool)(FE = Value.dyn_cast<FileEntry *> ()), true)) |
347 | return FE; |
348 | return getVirtualFile(*Value.get<const StringRef *>(), Size, |
349 | ModificationTime); |
350 | } |
351 | |
352 | // We've not seen this before, or the file is cached as non-existent. |
353 | ++NumFileCacheMisses; |
354 | addAncestorsAsVirtualDirs(Filename); |
355 | FileEntry *UFE = nullptr; |
356 | |
357 | // Now that all ancestors of Filename are in the cache, the |
358 | // following call is guaranteed to find the DirectoryEntry from the |
359 | // cache. |
360 | auto DirInfo = getDirectoryFromFile(*this, Filename, /*CacheFailure=*/true); |
361 | assert(DirInfo &&((DirInfo && "The directory of a virtual file should already be in the cache." ) ? static_cast<void> (0) : __assert_fail ("DirInfo && \"The directory of a virtual file should already be in the cache.\"" , "/build/llvm-toolchain-snapshot-12~++20201026111116+d3205bbca3e/clang/lib/Basic/FileManager.cpp" , 362, __PRETTY_FUNCTION__)) |
362 | "The directory of a virtual file should already be in the cache.")((DirInfo && "The directory of a virtual file should already be in the cache." ) ? static_cast<void> (0) : __assert_fail ("DirInfo && \"The directory of a virtual file should already be in the cache.\"" , "/build/llvm-toolchain-snapshot-12~++20201026111116+d3205bbca3e/clang/lib/Basic/FileManager.cpp" , 362, __PRETTY_FUNCTION__)); |
363 | |
364 | // Check to see if the file exists. If so, drop the virtual file |
365 | llvm::vfs::Status Status; |
366 | const char *InterndFileName = NamedFileEnt.first().data(); |
367 | if (!getStatValue(InterndFileName, Status, true, nullptr)) { |
368 | UFE = &UniqueRealFiles[Status.getUniqueID()]; |
369 | Status = llvm::vfs::Status( |
370 | Status.getName(), Status.getUniqueID(), |
371 | llvm::sys::toTimePoint(ModificationTime), |
372 | Status.getUser(), Status.getGroup(), Size, |
373 | Status.getType(), Status.getPermissions()); |
374 | |
375 | NamedFileEnt.second = UFE; |
376 | |
377 | // If we had already opened this file, close it now so we don't |
378 | // leak the descriptor. We're not going to use the file |
379 | // descriptor anyway, since this is a virtual file. |
380 | if (UFE->File) |
381 | UFE->closeFile(); |
382 | |
383 | // If we already have an entry with this inode, return it. |
384 | if (UFE->isValid()) |
385 | return UFE; |
386 | |
387 | UFE->UniqueID = Status.getUniqueID(); |
388 | UFE->IsNamedPipe = Status.getType() == llvm::sys::fs::file_type::fifo_file; |
389 | fillRealPathName(UFE, Status.getName()); |
390 | } else { |
391 | VirtualFileEntries.push_back(std::make_unique<FileEntry>()); |
392 | UFE = VirtualFileEntries.back().get(); |
393 | NamedFileEnt.second = UFE; |
394 | } |
395 | |
396 | UFE->Name = InterndFileName; |
397 | UFE->Size = Size; |
398 | UFE->ModTime = ModificationTime; |
399 | UFE->Dir = *DirInfo; |
400 | UFE->UID = NextFileUID++; |
401 | UFE->IsValid = true; |
402 | UFE->File.reset(); |
403 | return UFE; |
404 | } |
405 | |
406 | llvm::Optional<FileEntryRef> FileManager::getBypassFile(FileEntryRef VF) { |
407 | // Stat of the file and return nullptr if it doesn't exist. |
408 | llvm::vfs::Status Status; |
409 | if (getStatValue(VF.getName(), Status, /*isFile=*/true, /*F=*/nullptr)) |
410 | return None; |
411 | |
412 | // Fill it in from the stat. |
413 | BypassFileEntries.push_back(std::make_unique<FileEntry>()); |
414 | const FileEntry &VFE = VF.getFileEntry(); |
415 | FileEntry &BFE = *BypassFileEntries.back(); |
416 | BFE.Name = VFE.getName(); |
417 | BFE.Size = Status.getSize(); |
418 | BFE.Dir = VFE.Dir; |
419 | BFE.ModTime = llvm::sys::toTimeT(Status.getLastModificationTime()); |
420 | BFE.UID = NextFileUID++; |
421 | BFE.IsValid = true; |
422 | return FileEntryRef(VF.getName(), BFE); |
423 | } |
424 | |
425 | bool FileManager::FixupRelativePath(SmallVectorImpl<char> &path) const { |
426 | StringRef pathRef(path.data(), path.size()); |
427 | |
428 | if (FileSystemOpts.WorkingDir.empty() |
429 | || llvm::sys::path::is_absolute(pathRef)) |
430 | return false; |
431 | |
432 | SmallString<128> NewPath(FileSystemOpts.WorkingDir); |
433 | llvm::sys::path::append(NewPath, pathRef); |
434 | path = NewPath; |
435 | return true; |
436 | } |
437 | |
438 | bool FileManager::makeAbsolutePath(SmallVectorImpl<char> &Path) const { |
439 | bool Changed = FixupRelativePath(Path); |
440 | |
441 | if (!llvm::sys::path::is_absolute(StringRef(Path.data(), Path.size()))) { |
442 | FS->makeAbsolute(Path); |
443 | Changed = true; |
444 | } |
445 | |
446 | return Changed; |
447 | } |
448 | |
449 | void FileManager::fillRealPathName(FileEntry *UFE, llvm::StringRef FileName) { |
450 | llvm::SmallString<128> AbsPath(FileName); |
451 | // This is not the same as `VFS::getRealPath()`, which resolves symlinks |
452 | // but can be very expensive on real file systems. |
453 | // FIXME: the semantic of RealPathName is unclear, and the name might be |
454 | // misleading. We need to clean up the interface here. |
455 | makeAbsolutePath(AbsPath); |
456 | llvm::sys::path::remove_dots(AbsPath, /*remove_dot_dot=*/true); |
457 | UFE->RealPathName = std::string(AbsPath.str()); |
458 | } |
459 | |
460 | llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> |
461 | FileManager::getBufferForFile(const FileEntry *Entry, bool isVolatile, |
462 | bool RequiresNullTerminator) { |
463 | uint64_t FileSize = Entry->getSize(); |
464 | // If there's a high enough chance that the file have changed since we |
465 | // got its size, force a stat before opening it. |
466 | if (isVolatile) |
467 | FileSize = -1; |
468 | |
469 | StringRef Filename = Entry->getName(); |
470 | // If the file is already open, use the open file descriptor. |
471 | if (Entry->File) { |
472 | auto Result = Entry->File->getBuffer(Filename, FileSize, |
473 | RequiresNullTerminator, isVolatile); |
474 | Entry->closeFile(); |
475 | return Result; |
476 | } |
477 | |
478 | // Otherwise, open the file. |
479 | return getBufferForFileImpl(Filename, FileSize, isVolatile, |
480 | RequiresNullTerminator); |
481 | } |
482 | |
483 | llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> |
484 | FileManager::getBufferForFileImpl(StringRef Filename, int64_t FileSize, |
485 | bool isVolatile, |
486 | bool RequiresNullTerminator) { |
487 | if (FileSystemOpts.WorkingDir.empty()) |
488 | return FS->getBufferForFile(Filename, FileSize, RequiresNullTerminator, |
489 | isVolatile); |
490 | |
491 | SmallString<128> FilePath(Filename); |
492 | FixupRelativePath(FilePath); |
493 | return FS->getBufferForFile(FilePath, FileSize, RequiresNullTerminator, |
494 | isVolatile); |
495 | } |
496 | |
497 | /// getStatValue - Get the 'stat' information for the specified path, |
498 | /// using the cache to accelerate it if possible. This returns true |
499 | /// if the path points to a virtual file or does not exist, or returns |
500 | /// false if it's an existent real file. If FileDescriptor is NULL, |
501 | /// do directory look-up instead of file look-up. |
502 | std::error_code |
503 | FileManager::getStatValue(StringRef Path, llvm::vfs::Status &Status, |
504 | bool isFile, std::unique_ptr<llvm::vfs::File> *F) { |
505 | // FIXME: FileSystemOpts shouldn't be passed in here, all paths should be |
506 | // absolute! |
507 | if (FileSystemOpts.WorkingDir.empty()) |
508 | return FileSystemStatCache::get(Path, Status, isFile, F, |
509 | StatCache.get(), *FS); |
510 | |
511 | SmallString<128> FilePath(Path); |
512 | FixupRelativePath(FilePath); |
513 | |
514 | return FileSystemStatCache::get(FilePath.c_str(), Status, isFile, F, |
515 | StatCache.get(), *FS); |
516 | } |
517 | |
518 | std::error_code |
519 | FileManager::getNoncachedStatValue(StringRef Path, |
520 | llvm::vfs::Status &Result) { |
521 | SmallString<128> FilePath(Path); |
522 | FixupRelativePath(FilePath); |
523 | |
524 | llvm::ErrorOr<llvm::vfs::Status> S = FS->status(FilePath.c_str()); |
525 | if (!S) |
526 | return S.getError(); |
527 | Result = *S; |
528 | return std::error_code(); |
529 | } |
530 | |
531 | // For GNU Hurd |
532 | #if defined(__GNU__) && !defined(PATH_MAX4096) |
533 | # define PATH_MAX4096 4096 |
534 | #endif |
535 | |
536 | |
537 | void FileManager::GetUniqueIDMapping( |
538 | SmallVectorImpl<const FileEntry *> &UIDToFiles) const { |
539 | UIDToFiles.clear(); |
540 | UIDToFiles.resize(NextFileUID); |
541 | |
542 | // Map file entries |
543 | for (llvm::StringMap<llvm::ErrorOr<SeenFileEntryOrRedirect>, |
544 | llvm::BumpPtrAllocator>::const_iterator |
545 | FE = SeenFileEntries.begin(), |
546 | FEEnd = SeenFileEntries.end(); |
547 | FE != FEEnd; ++FE) |
548 | if (llvm::ErrorOr<SeenFileEntryOrRedirect> Entry = FE->getValue()) { |
549 | if (const auto *FE = (*Entry).dyn_cast<FileEntry *>()) |
550 | UIDToFiles[FE->getUID()] = FE; |
551 | } |
552 | |
553 | // Map virtual file entries |
554 | for (const auto &VFE : VirtualFileEntries) |
555 | UIDToFiles[VFE->getUID()] = VFE.get(); |
556 | } |
557 | |
558 | StringRef FileManager::getCanonicalName(const DirectoryEntry *Dir) { |
559 | llvm::DenseMap<const void *, llvm::StringRef>::iterator Known |
560 | = CanonicalNames.find(Dir); |
561 | if (Known != CanonicalNames.end()) |
562 | return Known->second; |
563 | |
564 | StringRef CanonicalName(Dir->getName()); |
565 | |
566 | SmallString<4096> CanonicalNameBuf; |
567 | if (!FS->getRealPath(Dir->getName(), CanonicalNameBuf)) |
568 | CanonicalName = StringRef(CanonicalNameBuf).copy(CanonicalNameStorage); |
569 | |
570 | CanonicalNames.insert({Dir, CanonicalName}); |
571 | return CanonicalName; |
572 | } |
573 | |
574 | StringRef FileManager::getCanonicalName(const FileEntry *File) { |
575 | llvm::DenseMap<const void *, llvm::StringRef>::iterator Known |
576 | = CanonicalNames.find(File); |
577 | if (Known != CanonicalNames.end()) |
578 | return Known->second; |
579 | |
580 | StringRef CanonicalName(File->getName()); |
581 | |
582 | SmallString<4096> CanonicalNameBuf; |
583 | if (!FS->getRealPath(File->getName(), CanonicalNameBuf)) |
584 | CanonicalName = StringRef(CanonicalNameBuf).copy(CanonicalNameStorage); |
585 | |
586 | CanonicalNames.insert({File, CanonicalName}); |
587 | return CanonicalName; |
588 | } |
589 | |
590 | void FileManager::PrintStats() const { |
591 | llvm::errs() << "\n*** File Manager Stats:\n"; |
592 | llvm::errs() << UniqueRealFiles.size() << " real files found, " |
593 | << UniqueRealDirs.size() << " real dirs found.\n"; |
594 | llvm::errs() << VirtualFileEntries.size() << " virtual files found, " |
595 | << VirtualDirectoryEntries.size() << " virtual dirs found.\n"; |
596 | llvm::errs() << NumDirLookups << " dir lookups, " |
597 | << NumDirCacheMisses << " dir cache misses.\n"; |
598 | llvm::errs() << NumFileLookups << " file lookups, " |
599 | << NumFileCacheMisses << " file cache misses.\n"; |
600 | |
601 | //llvm::errs() << PagesMapped << BytesOfPagesMapped << FSLookups; |
602 | } |