1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | #include "clang/Basic/FileManager.h" |
20 | #include "clang/Basic/FileSystemStatCache.h" |
21 | #include "llvm/ADT/SmallString.h" |
22 | #include "llvm/Config/llvm-config.h" |
23 | #include "llvm/ADT/STLExtras.h" |
24 | #include "llvm/Support/FileSystem.h" |
25 | #include "llvm/Support/MemoryBuffer.h" |
26 | #include "llvm/Support/Path.h" |
27 | #include "llvm/Support/raw_ostream.h" |
28 | #include <algorithm> |
29 | #include <cassert> |
30 | #include <climits> |
31 | #include <cstdint> |
32 | #include <cstdlib> |
33 | #include <string> |
34 | #include <utility> |
35 | |
36 | using namespace clang; |
37 | |
38 | |
39 | |
40 | |
41 | |
42 | FileManager::FileManager(const FileSystemOptions &FSO, |
43 | IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) |
44 | : FS(std::move(FS)), FileSystemOpts(FSO), SeenDirEntries(64), |
45 | SeenFileEntries(64), NextFileUID(0) { |
46 | NumDirLookups = NumFileLookups = 0; |
47 | NumDirCacheMisses = NumFileCacheMisses = 0; |
48 | |
49 | |
50 | |
51 | if (!this->FS) |
52 | this->FS = llvm::vfs::getRealFileSystem(); |
53 | } |
54 | |
55 | FileManager::~FileManager() = default; |
56 | |
57 | void FileManager::setStatCache(std::unique_ptr<FileSystemStatCache> statCache) { |
58 | (0) . __assert_fail ("statCache && \"No stat cache provided?\"", "/home/seafit/code_projects/clang_source/clang/lib/Basic/FileManager.cpp", 58, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(statCache && "No stat cache provided?"); |
59 | StatCache = std::move(statCache); |
60 | } |
61 | |
62 | void FileManager::clearStatCache() { StatCache.reset(); } |
63 | |
64 | |
65 | |
66 | static const DirectoryEntry *getDirectoryFromFile(FileManager &FileMgr, |
67 | StringRef Filename, |
68 | bool CacheFailure) { |
69 | if (Filename.empty()) |
70 | return nullptr; |
71 | |
72 | if (llvm::sys::path::is_separator(Filename[Filename.size() - 1])) |
73 | return nullptr; |
74 | |
75 | StringRef DirName = llvm::sys::path::parent_path(Filename); |
76 | |
77 | if (DirName.empty()) |
78 | DirName = "."; |
79 | |
80 | return FileMgr.getDirectory(DirName, CacheFailure); |
81 | } |
82 | |
83 | |
84 | |
85 | void FileManager::addAncestorsAsVirtualDirs(StringRef Path) { |
86 | StringRef DirName = llvm::sys::path::parent_path(Path); |
87 | if (DirName.empty()) |
88 | DirName = "."; |
89 | |
90 | auto &NamedDirEnt = *SeenDirEntries.insert({DirName, nullptr}).first; |
91 | |
92 | |
93 | |
94 | |
95 | |
96 | if (NamedDirEnt.second) |
97 | return; |
98 | |
99 | |
100 | auto UDE = llvm::make_unique<DirectoryEntry>(); |
101 | UDE->Name = NamedDirEnt.first(); |
102 | NamedDirEnt.second = UDE.get(); |
103 | VirtualDirectoryEntries.push_back(std::move(UDE)); |
104 | |
105 | |
106 | addAncestorsAsVirtualDirs(DirName); |
107 | } |
108 | |
109 | const DirectoryEntry *FileManager::getDirectory(StringRef DirName, |
110 | bool CacheFailure) { |
111 | |
112 | |
113 | |
114 | if (DirName.size() > 1 && |
115 | DirName != llvm::sys::path::root_path(DirName) && |
116 | llvm::sys::path::is_separator(DirName.back())) |
117 | DirName = DirName.substr(0, DirName.size()-1); |
118 | #ifdef _WIN32 |
119 | |
120 | |
121 | std::string DirNameStr; |
122 | if (DirName.size() > 1 && DirName.back() == ':' && |
123 | DirName.equals_lower(llvm::sys::path::root_name(DirName))) { |
124 | DirNameStr = DirName.str() + '.'; |
125 | DirName = DirNameStr; |
126 | } |
127 | #endif |
128 | |
129 | ++NumDirLookups; |
130 | |
131 | |
132 | |
133 | auto SeenDirInsertResult = SeenDirEntries.insert({DirName, nullptr}); |
134 | if (!SeenDirInsertResult.second) |
135 | return SeenDirInsertResult.first->second; |
136 | |
137 | |
138 | ++NumDirCacheMisses; |
139 | auto &NamedDirEnt = *SeenDirInsertResult.first; |
140 | (0) . __assert_fail ("!NamedDirEnt.second && \"should be newly-created\"", "/home/seafit/code_projects/clang_source/clang/lib/Basic/FileManager.cpp", 140, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(!NamedDirEnt.second && "should be newly-created"); |
141 | |
142 | |
143 | |
144 | StringRef InterndDirName = NamedDirEnt.first(); |
145 | |
146 | |
147 | llvm::vfs::Status Status; |
148 | if (getStatValue(InterndDirName, Status, false, nullptr )) { |
149 | |
150 | if (!CacheFailure) |
151 | SeenDirEntries.erase(DirName); |
152 | return nullptr; |
153 | } |
154 | |
155 | |
156 | |
157 | |
158 | |
159 | DirectoryEntry &UDE = UniqueRealDirs[Status.getUniqueID()]; |
160 | |
161 | NamedDirEnt.second = &UDE; |
162 | if (UDE.getName().empty()) { |
163 | |
164 | |
165 | UDE.Name = InterndDirName; |
166 | } |
167 | |
168 | return &UDE; |
169 | } |
170 | |
171 | const FileEntry *FileManager::getFile(StringRef Filename, bool openFile, |
172 | bool CacheFailure) { |
173 | ++NumFileLookups; |
174 | |
175 | |
176 | auto SeenFileInsertResult = SeenFileEntries.insert({Filename, nullptr}); |
177 | if (!SeenFileInsertResult.second) |
178 | return SeenFileInsertResult.first->second; |
179 | |
180 | |
181 | ++NumFileCacheMisses; |
182 | auto &NamedFileEnt = *SeenFileInsertResult.first; |
183 | (0) . __assert_fail ("!NamedFileEnt.second && \"should be newly-created\"", "/home/seafit/code_projects/clang_source/clang/lib/Basic/FileManager.cpp", 183, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(!NamedFileEnt.second && "should be newly-created"); |
184 | |
185 | |
186 | |
187 | StringRef InterndFileName = NamedFileEnt.first(); |
188 | |
189 | |
190 | |
191 | |
192 | |
193 | |
194 | const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename, |
195 | CacheFailure); |
196 | if (DirInfo == nullptr) { |
197 | if (!CacheFailure) |
198 | SeenFileEntries.erase(Filename); |
199 | |
200 | return nullptr; |
201 | } |
202 | |
203 | |
204 | |
205 | |
206 | |
207 | std::unique_ptr<llvm::vfs::File> F; |
208 | llvm::vfs::Status Status; |
209 | if (getStatValue(InterndFileName, Status, true, openFile ? &F : nullptr)) { |
210 | |
211 | if (!CacheFailure) |
212 | SeenFileEntries.erase(Filename); |
213 | |
214 | return nullptr; |
215 | } |
216 | |
217 | (0) . __assert_fail ("(openFile || !F) && \"undesired open file\"", "/home/seafit/code_projects/clang_source/clang/lib/Basic/FileManager.cpp", 217, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert((openFile || !F) && "undesired open file"); |
218 | |
219 | |
220 | |
221 | FileEntry &UFE = UniqueRealFiles[Status.getUniqueID()]; |
222 | |
223 | NamedFileEnt.second = &UFE; |
224 | |
225 | |
226 | |
227 | if (Status.getName() != Filename) { |
228 | auto &NamedFileEnt = |
229 | *SeenFileEntries.insert({Status.getName(), &UFE}).first; |
230 | (0) . __assert_fail ("NamedFileEnt.second == &UFE && \"filename from getStatValue() refers to wrong file\"", "/home/seafit/code_projects/clang_source/clang/lib/Basic/FileManager.cpp", 231, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(NamedFileEnt.second == &UFE && |
231 | (0) . __assert_fail ("NamedFileEnt.second == &UFE && \"filename from getStatValue() refers to wrong file\"", "/home/seafit/code_projects/clang_source/clang/lib/Basic/FileManager.cpp", 231, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> "filename from getStatValue() refers to wrong file"); |
232 | InterndFileName = NamedFileEnt.first().data(); |
233 | } |
234 | |
235 | if (UFE.isValid()) { |
236 | |
237 | |
238 | |
239 | |
240 | |
241 | |
242 | |
243 | if (DirInfo != UFE.Dir && Status.IsVFSMapped) |
244 | UFE.Dir = DirInfo; |
245 | |
246 | |
247 | |
248 | |
249 | |
250 | |
251 | UFE.Name = InterndFileName; |
252 | |
253 | return &UFE; |
254 | } |
255 | |
256 | |
257 | UFE.Name = InterndFileName; |
258 | UFE.Size = Status.getSize(); |
259 | UFE.ModTime = llvm::sys::toTimeT(Status.getLastModificationTime()); |
260 | UFE.Dir = DirInfo; |
261 | UFE.UID = NextFileUID++; |
262 | UFE.UniqueID = Status.getUniqueID(); |
263 | UFE.IsNamedPipe = Status.getType() == llvm::sys::fs::file_type::fifo_file; |
264 | UFE.File = std::move(F); |
265 | UFE.IsValid = true; |
266 | |
267 | if (UFE.File) { |
268 | if (auto PathName = UFE.File->getName()) |
269 | fillRealPathName(&UFE, *PathName); |
270 | } else if (!openFile) { |
271 | |
272 | fillRealPathName(&UFE, InterndFileName); |
273 | } |
274 | return &UFE; |
275 | } |
276 | |
277 | const FileEntry * |
278 | FileManager::getVirtualFile(StringRef Filename, off_t Size, |
279 | time_t ModificationTime) { |
280 | ++NumFileLookups; |
281 | |
282 | |
283 | auto &NamedFileEnt = *SeenFileEntries.insert({Filename, nullptr}).first; |
284 | if (NamedFileEnt.second) |
285 | return NamedFileEnt.second; |
286 | |
287 | |
288 | ++NumFileCacheMisses; |
289 | addAncestorsAsVirtualDirs(Filename); |
290 | FileEntry *UFE = nullptr; |
291 | |
292 | |
293 | |
294 | |
295 | const DirectoryEntry *DirInfo = getDirectoryFromFile(*this, Filename, |
296 | ); |
297 | (0) . __assert_fail ("DirInfo && \"The directory of a virtual file should already be in the cache.\"", "/home/seafit/code_projects/clang_source/clang/lib/Basic/FileManager.cpp", 298, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(DirInfo && |
298 | (0) . __assert_fail ("DirInfo && \"The directory of a virtual file should already be in the cache.\"", "/home/seafit/code_projects/clang_source/clang/lib/Basic/FileManager.cpp", 298, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> "The directory of a virtual file should already be in the cache."); |
299 | |
300 | |
301 | llvm::vfs::Status Status; |
302 | const char *InterndFileName = NamedFileEnt.first().data(); |
303 | if (getStatValue(InterndFileName, Status, true, nullptr) == 0) { |
304 | UFE = &UniqueRealFiles[Status.getUniqueID()]; |
305 | Status = llvm::vfs::Status( |
306 | Status.getName(), Status.getUniqueID(), |
307 | llvm::sys::toTimePoint(ModificationTime), |
308 | Status.getUser(), Status.getGroup(), Size, |
309 | Status.getType(), Status.getPermissions()); |
310 | |
311 | NamedFileEnt.second = UFE; |
312 | |
313 | |
314 | |
315 | |
316 | if (UFE->File) |
317 | UFE->closeFile(); |
318 | |
319 | |
320 | if (UFE->isValid()) |
321 | return UFE; |
322 | |
323 | UFE->UniqueID = Status.getUniqueID(); |
324 | UFE->IsNamedPipe = Status.getType() == llvm::sys::fs::file_type::fifo_file; |
325 | fillRealPathName(UFE, Status.getName()); |
326 | } else { |
327 | VirtualFileEntries.push_back(llvm::make_unique<FileEntry>()); |
328 | UFE = VirtualFileEntries.back().get(); |
329 | NamedFileEnt.second = UFE; |
330 | } |
331 | |
332 | UFE->Name = InterndFileName; |
333 | UFE->Size = Size; |
334 | UFE->ModTime = ModificationTime; |
335 | UFE->Dir = DirInfo; |
336 | UFE->UID = NextFileUID++; |
337 | UFE->IsValid = true; |
338 | UFE->File.reset(); |
339 | return UFE; |
340 | } |
341 | |
342 | bool FileManager::FixupRelativePath(SmallVectorImpl<char> &path) const { |
343 | StringRef pathRef(path.data(), path.size()); |
344 | |
345 | if (FileSystemOpts.WorkingDir.empty() |
346 | || llvm::sys::path::is_absolute(pathRef)) |
347 | return false; |
348 | |
349 | SmallString<128> NewPath(FileSystemOpts.WorkingDir); |
350 | llvm::sys::path::append(NewPath, pathRef); |
351 | path = NewPath; |
352 | return true; |
353 | } |
354 | |
355 | bool FileManager::makeAbsolutePath(SmallVectorImpl<char> &Path) const { |
356 | bool Changed = FixupRelativePath(Path); |
357 | |
358 | if (!llvm::sys::path::is_absolute(StringRef(Path.data(), Path.size()))) { |
359 | FS->makeAbsolute(Path); |
360 | Changed = true; |
361 | } |
362 | |
363 | return Changed; |
364 | } |
365 | |
366 | void FileManager::fillRealPathName(FileEntry *UFE, llvm::StringRef FileName) { |
367 | llvm::SmallString<128> AbsPath(FileName); |
368 | |
369 | |
370 | |
371 | |
372 | makeAbsolutePath(AbsPath); |
373 | llvm::sys::path::remove_dots(AbsPath, ); |
374 | UFE->RealPathName = AbsPath.str(); |
375 | } |
376 | |
377 | llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> |
378 | FileManager::getBufferForFile(const FileEntry *Entry, bool isVolatile, |
379 | bool ShouldCloseOpenFile) { |
380 | uint64_t FileSize = Entry->getSize(); |
381 | |
382 | |
383 | if (isVolatile) |
384 | FileSize = -1; |
385 | |
386 | StringRef Filename = Entry->getName(); |
387 | |
388 | if (Entry->File) { |
389 | auto Result = |
390 | Entry->File->getBuffer(Filename, FileSize, |
391 | , isVolatile); |
392 | |
393 | |
394 | if (ShouldCloseOpenFile) |
395 | Entry->closeFile(); |
396 | return Result; |
397 | } |
398 | |
399 | |
400 | |
401 | if (FileSystemOpts.WorkingDir.empty()) |
402 | return FS->getBufferForFile(Filename, FileSize, |
403 | , isVolatile); |
404 | |
405 | SmallString<128> FilePath(Entry->getName()); |
406 | FixupRelativePath(FilePath); |
407 | return FS->getBufferForFile(FilePath, FileSize, |
408 | , isVolatile); |
409 | } |
410 | |
411 | llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> |
412 | FileManager::getBufferForFile(StringRef Filename, bool isVolatile) { |
413 | if (FileSystemOpts.WorkingDir.empty()) |
414 | return FS->getBufferForFile(Filename, -1, true, isVolatile); |
415 | |
416 | SmallString<128> FilePath(Filename); |
417 | FixupRelativePath(FilePath); |
418 | return FS->getBufferForFile(FilePath.c_str(), -1, true, isVolatile); |
419 | } |
420 | |
421 | |
422 | |
423 | |
424 | |
425 | |
426 | bool FileManager::getStatValue(StringRef Path, llvm::vfs::Status &Status, |
427 | bool isFile, |
428 | std::unique_ptr<llvm::vfs::File> *F) { |
429 | |
430 | |
431 | if (FileSystemOpts.WorkingDir.empty()) |
432 | return FileSystemStatCache::get(Path, Status, isFile, F,StatCache.get(), *FS); |
433 | |
434 | SmallString<128> FilePath(Path); |
435 | FixupRelativePath(FilePath); |
436 | |
437 | return FileSystemStatCache::get(FilePath.c_str(), Status, isFile, F, |
438 | StatCache.get(), *FS); |
439 | } |
440 | |
441 | bool FileManager::getNoncachedStatValue(StringRef Path, |
442 | llvm::vfs::Status &Result) { |
443 | SmallString<128> FilePath(Path); |
444 | FixupRelativePath(FilePath); |
445 | |
446 | llvm::ErrorOr<llvm::vfs::Status> S = FS->status(FilePath.c_str()); |
447 | if (!S) |
448 | return true; |
449 | Result = *S; |
450 | return false; |
451 | } |
452 | |
453 | void FileManager::invalidateCache(const FileEntry *Entry) { |
454 | (0) . __assert_fail ("Entry && \"Cannot invalidate a NULL FileEntry\"", "/home/seafit/code_projects/clang_source/clang/lib/Basic/FileManager.cpp", 454, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Entry && "Cannot invalidate a NULL FileEntry"); |
455 | |
456 | SeenFileEntries.erase(Entry->getName()); |
457 | |
458 | |
459 | |
460 | |
461 | |
462 | |
463 | |
464 | UniqueRealFiles.erase(Entry->getUniqueID()); |
465 | } |
466 | |
467 | void FileManager::GetUniqueIDMapping( |
468 | SmallVectorImpl<const FileEntry *> &UIDToFiles) const { |
469 | UIDToFiles.clear(); |
470 | UIDToFiles.resize(NextFileUID); |
471 | |
472 | |
473 | for (llvm::StringMap<FileEntry*, llvm::BumpPtrAllocator>::const_iterator |
474 | FE = SeenFileEntries.begin(), FEEnd = SeenFileEntries.end(); |
475 | FE != FEEnd; ++FE) |
476 | if (FE->getValue()) |
477 | UIDToFiles[FE->getValue()->getUID()] = FE->getValue(); |
478 | |
479 | |
480 | for (const auto &VFE : VirtualFileEntries) |
481 | UIDToFiles[VFE->getUID()] = VFE.get(); |
482 | } |
483 | |
484 | void FileManager::modifyFileEntry(FileEntry *File, |
485 | off_t Size, time_t ModificationTime) { |
486 | File->Size = Size; |
487 | File->ModTime = ModificationTime; |
488 | } |
489 | |
490 | StringRef FileManager::getCanonicalName(const DirectoryEntry *Dir) { |
491 | |
492 | llvm::DenseMap<const DirectoryEntry *, llvm::StringRef>::iterator Known |
493 | = CanonicalDirNames.find(Dir); |
494 | if (Known != CanonicalDirNames.end()) |
495 | return Known->second; |
496 | |
497 | StringRef CanonicalName(Dir->getName()); |
498 | |
499 | SmallString<4096> CanonicalNameBuf; |
500 | if (!FS->getRealPath(Dir->getName(), CanonicalNameBuf)) |
501 | CanonicalName = StringRef(CanonicalNameBuf).copy(CanonicalNameStorage); |
502 | |
503 | CanonicalDirNames.insert({Dir, CanonicalName}); |
504 | return CanonicalName; |
505 | } |
506 | |
507 | void FileManager::PrintStats() const { |
508 | llvm::errs() << "\n*** File Manager Stats:\n"; |
509 | llvm::errs() << UniqueRealFiles.size() << " real files found, " |
510 | << UniqueRealDirs.size() << " real dirs found.\n"; |
511 | llvm::errs() << VirtualFileEntries.size() << " virtual files found, " |
512 | << VirtualDirectoryEntries.size() << " virtual dirs found.\n"; |
513 | llvm::errs() << NumDirLookups << " dir lookups, " |
514 | << NumDirCacheMisses << " dir cache misses.\n"; |
515 | llvm::errs() << NumFileLookups << " file lookups, " |
516 | << NumFileCacheMisses << " file cache misses.\n"; |
517 | |
518 | |
519 | } |
520 | |