LLVM 22.0.0git
FileCollector.cpp
Go to the documentation of this file.
1//===-- FileCollector.cpp ---------------------------------------*- C++ -*-===//
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
11#include "llvm/ADT/Twine.h"
13#include "llvm/Support/Path.h"
15
16using namespace llvm;
17
20
22 std::lock_guard<std::mutex> lock(Mutex);
23 std::string FileStr = File.str();
24 if (markAsSeen(FileStr))
25 addFileImpl(FileStr);
26}
27
30 std::error_code EC;
32}
33
34static bool isCaseSensitivePath(StringRef Path) {
35 SmallString<256> TmpDest = Path, UpperDest, RealDest;
36
37 // Remove component traversals, links, etc.
38 if (sys::fs::real_path(Path, TmpDest))
39 return true; // Current default value in vfs.yaml
40 Path = TmpDest;
41
42 // Change path to all upper case and ask for its real path, if the latter
43 // exists and is equal to path, it's not case sensitive. Default to case
44 // sensitive in the absence of real_path, since this is the YAMLVFSWriter
45 // default.
46 UpperDest = Path.upper();
47 if (!sys::fs::real_path(UpperDest, RealDest) && Path == RealDest)
48 return false;
49 return true;
50}
51
55 assert(sys::path::is_absolute(Root) && "Root not absolute");
56 assert(sys::path::is_absolute(OverlayRoot) && "OverlayRoot not absolute");
57}
58
59void FileCollector::PathCanonicalizer::updateWithRealPath(
61 StringRef SrcPath(Path.begin(), Path.size());
62 StringRef Filename = sys::path::filename(SrcPath);
63 StringRef Directory = sys::path::parent_path(SrcPath);
64
65 // Use real_path to fix any symbolic link component present in the directory
66 // part of the path, caching the search because computing the real path is
67 // expensive.
68 SmallString<256> RealPath;
69 auto DirWithSymlink = CachedDirs.find(Directory);
70 if (DirWithSymlink == CachedDirs.end()) {
71 // FIXME: Should this be a call to FileSystem::getRealpath(), in some
72 // cases? What if there is nothing on disk?
73 if (sys::fs::real_path(Directory, RealPath))
74 return;
75 CachedDirs[Directory] = std::string(RealPath);
76 } else {
77 RealPath = DirWithSymlink->second;
78 }
79
80 // Finish recreating the path by appending the original filename, since we
81 // don't need to resolve symlinks in the filename.
82 //
83 // FIXME: If we can cope with this, maybe we can cope without calling
84 // getRealPath() at all when there's no ".." component.
85 sys::path::append(RealPath, Filename);
86
87 // Swap to create the output.
88 Path.swap(RealPath);
89}
90
91/// Make Path absolute.
93 // We need an absolute src path to append to the root.
94 VFS.makeAbsolute(Path);
95
96 // Canonicalize src to a native path to avoid mixed separator styles.
98
99 // Remove redundant leading "./" pieces and consecutive separators.
100 Path.erase(Path.begin(), sys::path::remove_leading_dotslash(
101 StringRef(Path.begin(), Path.size()))
102 .begin());
103}
104
105FileCollector::PathCanonicalizer::PathStorage
107 PathStorage Paths;
108 Paths.VirtualPath = SrcPath;
109 makeAbsolute(*VFS, Paths.VirtualPath);
110
111 // If a ".." component is present after a symlink component, remove_dots may
112 // lead to the wrong real destination path. Let the source be canonicalized
113 // like that but make sure we always use the real path for the destination.
114 Paths.CopyFrom = Paths.VirtualPath;
115 updateWithRealPath(Paths.CopyFrom);
116
117 // Canonicalize the virtual path by removing "..", "." components.
118 sys::path::remove_dots(Paths.VirtualPath, /*remove_dot_dot=*/true);
119
120 return Paths;
121}
122
124 PathCanonicalizer::PathStorage Paths = Canonicalizer.canonicalize(SrcPath);
125
128
129 // Always map a canonical src path to its real path into the YAML, by doing
130 // this we map different virtual src paths to the same entry in the VFS
131 // overlay, which is a way to emulate symlink inside the VFS; this is also
132 // needed for correctness, not doing that can lead to module redefinition
133 // errors.
134 addFileToMapping(Paths.VirtualPath, DstPath);
135}
136
140 std::error_code &EC) {
141 auto It = FS->dir_begin(Dir, EC);
142 if (EC)
143 return It;
144 addFile(Dir);
145 for (; !EC && It != llvm::vfs::directory_iterator(); It.increment(EC)) {
146 if (It->type() == sys::fs::file_type::regular_file ||
148 It->type() == sys::fs::file_type::symlink_file) {
149 addFile(It->path());
150 }
151 }
152 if (EC)
153 return It;
154 // Return a new iterator.
155 return FS->dir_begin(Dir, EC);
156}
157
158/// Set the access and modification time for the given file from the given
159/// status object.
160static std::error_code
162 const sys::fs::file_status &Stat) {
163 int FD;
164
165 if (auto EC =
167 return EC;
168
171 return EC;
172
174 return EC;
175
176 return {};
177}
178
179std::error_code FileCollector::copyFiles(bool StopOnError) {
180 auto Err = sys::fs::create_directories(Root, /*IgnoreExisting=*/true);
181 if (Err) {
182 return Err;
183 }
184
185 std::lock_guard<std::mutex> lock(Mutex);
186
187 for (auto &entry : VFSWriter.getMappings()) {
188 // Get the status of the original file/directory.
190 if (std::error_code EC = sys::fs::status(entry.VPath, Stat)) {
191 if (StopOnError)
192 return EC;
193 continue;
194 }
195
196 // Continue if the file doesn't exist.
198 continue;
199
200 // Create directory tree.
201 if (std::error_code EC =
203 /*IgnoreExisting=*/true)) {
204 if (StopOnError)
205 return EC;
206 }
207
209 // Construct a directory when it's just a directory entry.
210 if (std::error_code EC =
211 sys::fs::create_directories(entry.RPath,
212 /*IgnoreExisting=*/true)) {
213 if (StopOnError)
214 return EC;
215 }
216 continue;
217 }
218
219 // Copy file over.
220 if (std::error_code EC = sys::fs::copy_file(entry.VPath, entry.RPath)) {
221 if (StopOnError)
222 return EC;
223 }
224
225 // Copy over permissions.
226 if (auto perms = sys::fs::getPermissions(entry.VPath)) {
227 if (std::error_code EC = sys::fs::setPermissions(entry.RPath, *perms)) {
228 if (StopOnError)
229 return EC;
230 }
231 }
232
233 // Copy over modification time.
234 copyAccessAndModificationTime(entry.RPath, Stat);
235 }
236 return {};
237}
238
239std::error_code FileCollector::writeMapping(StringRef MappingFile) {
240 std::lock_guard<std::mutex> lock(Mutex);
241
242 VFSWriter.setOverlayDir(OverlayRoot);
243 VFSWriter.setCaseSensitivity(isCaseSensitivePath(OverlayRoot));
244 VFSWriter.setUseExternalNames(false);
245
246 std::error_code EC;
247 raw_fd_ostream os(MappingFile, EC, sys::fs::OF_TextWithCRLF);
248 if (EC)
249 return EC;
250
251 VFSWriter.write(os);
252
253 return {};
254}
255
256namespace llvm {
257
259public:
261 std::shared_ptr<FileCollector> Collector)
262 : FS(std::move(FS)), Collector(std::move(Collector)) {}
263
265 auto Result = FS->status(Path);
266 if (Result && Result->exists())
267 Collector->addFile(Path);
268 return Result;
269 }
270
272 openFileForRead(const Twine &Path) override {
273 auto Result = FS->openFileForRead(Path);
274 if (Result && *Result)
275 Collector->addFile(Path);
276 return Result;
277 }
278
280 std::error_code &EC) override {
281 return Collector->addDirectoryImpl(Dir, FS, EC);
282 }
283
284 std::error_code getRealPath(const Twine &Path,
285 SmallVectorImpl<char> &Output) override {
286 auto EC = FS->getRealPath(Path, Output);
287 if (!EC) {
288 Collector->addFile(Path);
289 if (Output.size() > 0)
290 Collector->addFile(Output);
291 }
292 return EC;
293 }
294
295 std::error_code isLocal(const Twine &Path, bool &Result) override {
296 return FS->isLocal(Path, Result);
297 }
298
300 return FS->getCurrentWorkingDirectory();
301 }
302
303 std::error_code setCurrentWorkingDirectory(const llvm::Twine &Path) override {
304 return FS->setCurrentWorkingDirectory(Path);
305 }
306
307private:
309 std::shared_ptr<FileCollector> Collector;
310};
311
312} // namespace llvm
313
314IntrusiveRefCntPtr<vfs::FileSystem>
316 std::shared_ptr<FileCollector> Collector) {
317 return makeIntrusiveRefCnt<FileCollectorFileSystem>(std::move(BaseFS),
318 std::move(Collector));
319}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static std::error_code copyAccessAndModificationTime(StringRef Filename, const sys::fs::file_status &Stat)
Set the access and modification time for the given file from the given status object.
static bool isCaseSensitivePath(StringRef Path)
static void makeAbsolute(vfs::FileSystem &VFS, SmallVectorImpl< char > &Path)
Make Path absolute.
Provides a library for accessing information about this process and other processes on the operating ...
Register Usage Information Collector
This file defines the SmallString class.
Represents either an error or a value T.
Definition ErrorOr.h:56
std::mutex Mutex
Synchronizes access to internal data structures.
void addDirectory(const Twine &Dir)
void addFile(const Twine &file)
virtual llvm::vfs::directory_iterator addDirectoryImpl(const llvm::Twine &Dir, IntrusiveRefCntPtr< vfs::FileSystem > FS, std::error_code &EC)=0
bool markAsSeen(StringRef Path)
virtual void addFileImpl(StringRef SrcPath)=0
FileCollectorFileSystem(IntrusiveRefCntPtr< vfs::FileSystem > FS, std::shared_ptr< FileCollector > Collector)
std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output) override
Gets real path of Path e.g.
std::error_code setCurrentWorkingDirectory(const llvm::Twine &Path) override
Set the working directory.
std::error_code isLocal(const Twine &Path, bool &Result) override
Is the file mounted on a local filesystem?
llvm::ErrorOr< llvm::vfs::Status > status(const Twine &Path) override
Get the status of the entry at Path, if one exists.
llvm::ErrorOr< std::unique_ptr< llvm::vfs::File > > openFileForRead(const Twine &Path) override
Get a File object for the text file at Path, if one exists.
llvm::vfs::directory_iterator dir_begin(const llvm::Twine &Dir, std::error_code &EC) override
Get a directory_iterator for Dir.
llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const override
Get the working directory of this file system.
LLVM_ABI PathStorage canonicalize(StringRef SrcPath)
Canonicalize a pair of virtual and real paths.
llvm::vfs::directory_iterator addDirectoryImpl(const llvm::Twine &Dir, IntrusiveRefCntPtr< vfs::FileSystem > FS, std::error_code &EC) override
std::error_code writeMapping(StringRef MappingFile)
Write the yaml mapping (for the VFS) to the given file.
FileCollector(std::string Root, std::string OverlayRoot, IntrusiveRefCntPtr< vfs::FileSystem > VFS)
Root is the directory where collected files are will be stored.
std::error_code copyFiles(bool StopOnError=true)
Copy the files into the root directory.
const std::string OverlayRoot
The root directory where the VFS overlay lives.
PathCanonicalizer Canonicalizer
Helper utility for canonicalizing paths.
const std::string Root
The directory where collected files are copied to in copyFiles().
vfs::YAMLVFSWriter VFSWriter
The yaml mapping writer.
void addFileImpl(StringRef SrcPath) override
static IntrusiveRefCntPtr< vfs::FileSystem > createCollectorVFS(IntrusiveRefCntPtr< vfs::FileSystem > BaseFS, std::shared_ptr< FileCollector > Collector)
Create a VFS that uses Collector to collect files accessed via BaseFS.
A smart pointer to a reference-counted object that inherits from RefCountedBase or ThreadSafeRefCount...
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition SmallString.h:26
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
iterator end()
Definition StringMap.h:224
iterator find(StringRef Key)
Definition StringMap.h:235
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
A raw_ostream that writes to a file descriptor.
static LLVM_ABI std::error_code SafelyCloseFileDescriptor(int FD)
LLVM_ABI TimePoint getLastModificationTime() const
The file modification time as reported from the underlying file system.
LLVM_ABI TimePoint getLastAccessedTime() const
The file access time as reported from the underlying file system.
Represents the result of a call to sys::fs::status().
Definition FileSystem.h:222
The virtual file system interface.
virtual std::error_code makeAbsolute(SmallVectorImpl< char > &Path) const
Make Path an absolute path.
An input iterator over the entries in a virtual path, similar to llvm::sys::fs::directory_iterator.
LLVM_ABI ErrorOr< perms > getPermissions(const Twine &Path)
Get file permissions.
Definition Path.cpp:1151
@ OF_TextWithCRLF
The file should be opened in text mode and use a carriage linefeed '\r '.
Definition FileSystem.h:776
LLVM_ABI std::error_code real_path(const Twine &path, SmallVectorImpl< char > &output, bool expand_tilde=false)
Collapse all .
@ CD_OpenExisting
CD_OpenExisting - When opening a file:
Definition FileSystem.h:749
std::error_code openFileForWrite(const Twine &Name, int &ResultFD, CreationDisposition Disp=CD_CreateAlways, OpenFlags Flags=OF_None, unsigned Mode=0666)
Opens the file with the given name in a write-only or read-write mode, returning its open file descri...
LLVM_ABI std::error_code create_directories(const Twine &path, bool IgnoreExisting=true, perms Perms=owner_all|group_all)
Create all the non-existent directories in path.
Definition Path.cpp:967
LLVM_ABI std::error_code copy_file(const Twine &From, const Twine &To)
Copy the contents of From to To.
Definition Path.cpp:1016
LLVM_ABI std::error_code status(const Twine &path, file_status &result, bool follow=true)
Get file status as if by POSIX stat().
LLVM_ABI std::error_code setLastAccessAndModificationTime(int FD, TimePoint<> AccessTime, TimePoint<> ModificationTime)
Set the file modification and access time.
LLVM_ABI std::error_code setPermissions(const Twine &Path, perms Permissions)
Set file permissions.
LLVM_ABI bool is_directory(const basic_file_status &status)
Does status represent a directory?
Definition Path.cpp:1092
LLVM_ABI bool remove_dots(SmallVectorImpl< char > &path, bool remove_dot_dot=false, Style style=Style::native)
In-place remove any '.
Definition Path.cpp:715
LLVM_ABI StringRef parent_path(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get parent path.
Definition Path.cpp:467
LLVM_ABI StringRef filename(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get filename.
Definition Path.cpp:577
LLVM_ABI StringRef remove_leading_dotslash(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Remove redundant leading "./" pieces and consecutive separators.
LLVM_ABI bool is_absolute(const Twine &path, Style style=Style::native)
Is path absolute?
Definition Path.cpp:671
LLVM_ABI void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
Definition Path.cpp:456
LLVM_ABI StringRef relative_path(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)
Get relative path.
Definition Path.cpp:413
LLVM_ABI IntrusiveRefCntPtr< FileSystem > getRealFileSystem()
Gets an vfs::FileSystem for the 'real' file system, as seen by the operating system.
This is an optimization pass for GlobalISel generic memory operations.
IntrusiveRefCntPtr< T > makeIntrusiveRefCnt(Args &&...A)
Factory function for creating intrusive ref counted pointers.
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1847
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:870