/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Basic/FileSystemStatCache.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- FileSystemStatCache.cpp - Caching for 'stat' calls -----------------===// |
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 defines the FileSystemStatCache interface. |
10 | | // |
11 | | //===----------------------------------------------------------------------===// |
12 | | |
13 | | #include "clang/Basic/FileSystemStatCache.h" |
14 | | #include "llvm/Support/Chrono.h" |
15 | | #include "llvm/Support/ErrorOr.h" |
16 | | #include "llvm/Support/Path.h" |
17 | | #include "llvm/Support/VirtualFileSystem.h" |
18 | | #include <utility> |
19 | | |
20 | | using namespace clang; |
21 | | |
22 | 0 | void FileSystemStatCache::anchor() {} |
23 | | |
24 | | /// FileSystemStatCache::get - Get the 'stat' information for the specified |
25 | | /// path, using the cache to accelerate it if possible. This returns true if |
26 | | /// the path does not exist or false if it exists. |
27 | | /// |
28 | | /// If isFile is true, then this lookup should only return success for files |
29 | | /// (not directories). If it is false this lookup should only return |
30 | | /// success for directories (not files). On a successful file lookup, the |
31 | | /// implementation can optionally fill in FileDescriptor with a valid |
32 | | /// descriptor and the client guarantees that it will close it. |
33 | | std::error_code |
34 | | FileSystemStatCache::get(StringRef Path, llvm::vfs::Status &Status, |
35 | | bool isFile, std::unique_ptr<llvm::vfs::File> *F, |
36 | | FileSystemStatCache *Cache, |
37 | 4.34M | llvm::vfs::FileSystem &FS) { |
38 | 4.34M | bool isForDir = !isFile; |
39 | 4.34M | std::error_code RetCode; |
40 | | |
41 | | // If we have a cache, use it to resolve the stat query. |
42 | 4.34M | if (Cache) |
43 | 38 | RetCode = Cache->getStat(Path, Status, isFile, F, FS); |
44 | 4.34M | else if (isForDir || !F3.14M ) { |
45 | | // If this is a directory or a file descriptor is not needed and we have |
46 | | // no cache, just go to the file system. |
47 | 3.53M | llvm::ErrorOr<llvm::vfs::Status> StatusOrErr = FS.status(Path); |
48 | 3.53M | if (!StatusOrErr) { |
49 | 441k | RetCode = StatusOrErr.getError(); |
50 | 3.09M | } else { |
51 | 3.09M | Status = *StatusOrErr; |
52 | 3.09M | } |
53 | 3.53M | } else { |
54 | | // Otherwise, we have to go to the filesystem. We can always just use |
55 | | // 'stat' here, but (for files) the client is asking whether the file exists |
56 | | // because it wants to turn around and *open* it. It is more efficient to |
57 | | // do "open+fstat" on success than it is to do "stat+open". |
58 | | // |
59 | | // Because of this, check to see if the file exists with 'open'. If the |
60 | | // open succeeds, use fstat to get the stat info. |
61 | 808k | auto OwnedFile = FS.openFileForRead(Path); |
62 | | |
63 | 808k | if (!OwnedFile) { |
64 | | // If the open fails, our "stat" fails. |
65 | 239k | RetCode = OwnedFile.getError(); |
66 | 568k | } else { |
67 | | // Otherwise, the open succeeded. Do an fstat to get the information |
68 | | // about the file. We'll end up returning the open file descriptor to the |
69 | | // client to do what they please with it. |
70 | 568k | llvm::ErrorOr<llvm::vfs::Status> StatusOrErr = (*OwnedFile)->status(); |
71 | 568k | if (StatusOrErr) { |
72 | 568k | Status = *StatusOrErr; |
73 | 568k | *F = std::move(*OwnedFile); |
74 | 568k | } else { |
75 | | // fstat rarely fails. If it does, claim the initial open didn't |
76 | | // succeed. |
77 | 0 | *F = nullptr; |
78 | 0 | RetCode = StatusOrErr.getError(); |
79 | 0 | } |
80 | 568k | } |
81 | 808k | } |
82 | | |
83 | | // If the path doesn't exist, return failure. |
84 | 4.34M | if (RetCode) |
85 | 681k | return RetCode; |
86 | | |
87 | | // If the path exists, make sure that its "directoryness" matches the clients |
88 | | // demands. |
89 | 3.66M | if (Status.isDirectory() != isForDir) { |
90 | | // If not, close the file if opened. |
91 | 401k | if (F) |
92 | 1 | *F = nullptr; |
93 | 401k | return std::make_error_code( |
94 | 401k | Status.isDirectory() ? |
95 | 401k | std::errc::is_a_directory55 : std::errc::not_a_directory); |
96 | 401k | } |
97 | | |
98 | 3.26M | return std::error_code(); |
99 | 3.66M | } |
100 | | |
101 | | std::error_code |
102 | | MemorizeStatCalls::getStat(StringRef Path, llvm::vfs::Status &Status, |
103 | | bool isFile, |
104 | | std::unique_ptr<llvm::vfs::File> *F, |
105 | 0 | llvm::vfs::FileSystem &FS) { |
106 | 0 | auto err = get(Path, Status, isFile, F, nullptr, FS); |
107 | 0 | if (err) { |
108 | | // Do not cache failed stats, it is easy to construct common inconsistent |
109 | | // situations if we do, and they are not important for PCH performance |
110 | | // (which currently only needs the stats to construct the initial |
111 | | // FileManager entries). |
112 | 0 | return err; |
113 | 0 | } |
114 | | |
115 | | // Cache file 'stat' results and directories with absolutely paths. |
116 | 0 | if (!Status.isDirectory() || llvm::sys::path::is_absolute(Path)) |
117 | 0 | StatCalls[Path] = Status; |
118 | |
|
119 | 0 | return std::error_code(); |
120 | 0 | } |