LLVM  10.0.0svn
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 
10 #include "llvm/ADT/SmallString.h"
12 #include "llvm/Support/Path.h"
13 #include "llvm/Support/Process.h"
14 
15 using namespace llvm;
16 
17 static bool isCaseSensitivePath(StringRef Path) {
18  SmallString<256> TmpDest = Path, UpperDest, RealDest;
19 
20  // Remove component traversals, links, etc.
21  if (!sys::fs::real_path(Path, TmpDest))
22  return true; // Current default value in vfs.yaml
23  Path = TmpDest;
24 
25  // Change path to all upper case and ask for its real path, if the latter
26  // exists and is equal to path, it's not case sensitive. Default to case
27  // sensitive in the absence of real_path, since this is the YAMLVFSWriter
28  // default.
29  UpperDest = Path.upper();
30  if (sys::fs::real_path(UpperDest, RealDest) && Path.equals(RealDest))
31  return false;
32  return true;
33 }
34 
35 FileCollector::FileCollector(std::string Root, std::string OverlayRoot)
36  : Root(std::move(Root)), OverlayRoot(std::move(OverlayRoot)) {
37  sys::fs::create_directories(this->Root, true);
38 }
39 
40 bool FileCollector::getRealPath(StringRef SrcPath,
41  SmallVectorImpl<char> &Result) {
42  SmallString<256> RealPath;
43  StringRef FileName = sys::path::filename(SrcPath);
44  std::string Directory = sys::path::parent_path(SrcPath).str();
45  auto DirWithSymlink = SymlinkMap.find(Directory);
46 
47  // Use real_path to fix any symbolic link component present in a path.
48  // Computing the real path is expensive, cache the search through the parent
49  // path Directory.
50  if (DirWithSymlink == SymlinkMap.end()) {
51  auto EC = sys::fs::real_path(Directory, RealPath);
52  if (EC)
53  return false;
54  SymlinkMap[Directory] = RealPath.str();
55  } else {
56  RealPath = DirWithSymlink->second;
57  }
58 
59  sys::path::append(RealPath, FileName);
60  Result.swap(RealPath);
61  return true;
62 }
63 
65  std::lock_guard<std::mutex> lock(Mutex);
66  std::string FileStr = file.str();
67  if (markAsSeen(FileStr))
68  addFileImpl(FileStr);
69 }
70 
71 void FileCollector::addFileImpl(StringRef SrcPath) {
72  // We need an absolute src path to append to the root.
73  SmallString<256> AbsoluteSrc = SrcPath;
74  sys::fs::make_absolute(AbsoluteSrc);
75 
76  // Canonicalize src to a native path to avoid mixed separator styles.
77  sys::path::native(AbsoluteSrc);
78 
79  // Remove redundant leading "./" pieces and consecutive separators.
80  AbsoluteSrc = sys::path::remove_leading_dotslash(AbsoluteSrc);
81 
82  // Canonicalize the source path by removing "..", "." components.
83  SmallString<256> VirtualPath = AbsoluteSrc;
84  sys::path::remove_dots(VirtualPath, /*remove_dot_dot=*/true);
85 
86  // If a ".." component is present after a symlink component, remove_dots may
87  // lead to the wrong real destination path. Let the source be canonicalized
88  // like that but make sure we always use the real path for the destination.
89  SmallString<256> CopyFrom;
90  if (!getRealPath(AbsoluteSrc, CopyFrom))
91  CopyFrom = VirtualPath;
92 
93  SmallString<256> DstPath = StringRef(Root);
94  sys::path::append(DstPath, sys::path::relative_path(CopyFrom));
95 
96  // Always map a canonical src path to its real path into the YAML, by doing
97  // this we map different virtual src paths to the same entry in the VFS
98  // overlay, which is a way to emulate symlink inside the VFS; this is also
99  // needed for correctness, not doing that can lead to module redefinition
100  // errors.
101  addFileToMapping(VirtualPath, DstPath);
102 }
103 
104 /// Set the access and modification time for the given file from the given
105 /// status object.
106 static std::error_code
108  const sys::fs::file_status &Stat) {
109  int FD;
110 
111  if (auto EC =
113  return EC;
114 
116  FD, Stat.getLastAccessedTime(), Stat.getLastModificationTime()))
117  return EC;
118 
119  if (auto EC = sys::Process::SafelyCloseFileDescriptor(FD))
120  return EC;
121 
122  return {};
123 }
124 
125 std::error_code FileCollector::copyFiles(bool StopOnError) {
126  for (auto &entry : VFSWriter.getMappings()) {
127  // Create directory tree.
128  if (std::error_code EC =
130  /*IgnoreExisting=*/true)) {
131  if (StopOnError)
132  return EC;
133  }
134 
135  // Get the status of the original file/directory.
137  if (std::error_code EC = sys::fs::status(entry.VPath, Stat)) {
138  if (StopOnError)
139  return EC;
140  continue;
141  }
142 
144  // Construct a directory when it's just a directory entry.
145  if (std::error_code EC =
147  /*IgnoreExisting=*/true)) {
148  if (StopOnError)
149  return EC;
150  }
151  continue;
152  }
153 
154  // Copy file over.
155  if (std::error_code EC = sys::fs::copy_file(entry.VPath, entry.RPath)) {
156  if (StopOnError)
157  return EC;
158  }
159 
160  // Copy over permissions.
161  if (auto perms = sys::fs::getPermissions(entry.VPath)) {
162  if (std::error_code EC = sys::fs::setPermissions(entry.RPath, *perms)) {
163  if (StopOnError)
164  return EC;
165  }
166  }
167 
168  // Copy over modification time.
170  }
171  return {};
172 }
173 
174 std::error_code FileCollector::writeMapping(StringRef mapping_file) {
175  std::lock_guard<std::mutex> lock(Mutex);
176 
180 
181  std::error_code EC;
182  raw_fd_ostream os(mapping_file, EC, sys::fs::OF_Text);
183  if (EC)
184  return EC;
185 
186  VFSWriter.write(os);
187 
188  return {};
189 }
190 
191 namespace {
192 
193 class FileCollectorFileSystem : public vfs::FileSystem {
194 public:
195  explicit FileCollectorFileSystem(IntrusiveRefCntPtr<vfs::FileSystem> FS,
196  std::shared_ptr<FileCollector> Collector)
197  : FS(std::move(FS)), Collector(std::move(Collector)) {}
198 
199  llvm::ErrorOr<llvm::vfs::Status> status(const Twine &Path) override {
200  auto Result = FS->status(Path);
201  if (Result && Result->exists())
202  Collector->addFile(Path);
203  return Result;
204  }
205 
207  openFileForRead(const Twine &Path) override {
208  auto Result = FS->openFileForRead(Path);
209  if (Result && *Result)
210  Collector->addFile(Path);
211  return Result;
212  }
213 
214  llvm::vfs::directory_iterator dir_begin(const llvm::Twine &Dir,
215  std::error_code &EC) override {
216  auto It = FS->dir_begin(Dir, EC);
217  if (EC)
218  return It;
219  // Collect everything that's listed in case the user needs it.
220  Collector->addFile(Dir);
221  for (; !EC && It != llvm::vfs::directory_iterator(); It.increment(EC)) {
222  if (It->type() == sys::fs::file_type::regular_file ||
223  It->type() == sys::fs::file_type::directory_file ||
224  It->type() == sys::fs::file_type::symlink_file) {
225  Collector->addFile(It->path());
226  }
227  }
228  if (EC)
229  return It;
230  // Return a new iterator.
231  return FS->dir_begin(Dir, EC);
232  }
233 
234  std::error_code getRealPath(const Twine &Path,
235  SmallVectorImpl<char> &Output) const override {
236  auto EC = FS->getRealPath(Path, Output);
237  if (!EC) {
238  Collector->addFile(Path);
239  if (Output.size() > 0)
240  Collector->addFile(Output);
241  }
242  return EC;
243  }
244 
245  std::error_code isLocal(const Twine &Path, bool &Result) override {
246  return FS->isLocal(Path, Result);
247  }
248 
249  llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
250  return FS->getCurrentWorkingDirectory();
251  }
252 
253  std::error_code setCurrentWorkingDirectory(const llvm::Twine &Path) override {
254  return FS->setCurrentWorkingDirectory(Path);
255  }
256 
257 private:
259  std::shared_ptr<FileCollector> Collector;
260 };
261 
262 } // end anonymous namespace
263 
266  std::shared_ptr<FileCollector> Collector) {
267  return new FileCollectorFileSystem(std::move(BaseFS), std::move(Collector));
268 }
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:915
*ViewGraph Emit a dot run run gv on the postscript file
Definition: GraphWriter.h:362
Represents either an error or a value T.
Definition: ErrorOr.h:56
void native(const Twine &path, SmallVectorImpl< char > &result, Style style=Style::native)
Convert path to the native form.
Definition: Path.cpp:522
LLVM_NODISCARD std::string str() const
str - Get the contents as an std::string.
Definition: StringRef.h:232
This class represents lattice values for constants.
Definition: AllocatorList.h:23
std::error_code openFileForRead(const Twine &Name, int &ResultFD, OpenFlags Flags=OF_None, SmallVectorImpl< char > *RealPath=nullptr)
Opens the file with the given name in a read-only mode, returning its open file descriptor.
StringMap< std::string > SymlinkMap
Caches RealPath calls when resolving symlinks.
Definition: FileCollector.h:74
std::error_code setLastAccessAndModificationTime(int FD, TimePoint<> AccessTime, TimePoint<> ModificationTime)
Set the file modification and access time.
const std::vector< YAMLVFSEntry > & getMappings() const
iterator find(StringRef Key)
Definition: StringMap.h:332
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.
StringRef remove_leading_dotslash(StringRef path, Style style=Style::native)
Remove redundant leading "./" pieces and consecutive separators.
Definition: Path.cpp:678
Represents the result of a call to sys::fs::status().
Definition: FileSystem.h:246
CD_OpenExisting - When opening a file:
Definition: FileSystem.h:748
std::error_code copyFiles(bool StopOnError=true)
Copy the files into the root directory.
ErrorOr< perms > getPermissions(const Twine &Path)
Get file permissions.
Definition: Path.cpp:1099
void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")
Append to path.
Definition: Path.cpp:455
Definition: BitVector.h:937
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:80
void write(llvm::raw_ostream &OS)
void make_absolute(const Twine &current_directory, SmallVectorImpl< char > &path)
Make path an absolute path.
Definition: Path.cpp:853
std::string OverlayRoot
The root directory where the VFS overlay lives.
Definition: FileCollector.h:65
StringRef str() const
Explicit conversion to StringRef.
Definition: SmallString.h:266
void setCaseSensitivity(bool CaseSensitive)
virtual llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const =0
Get the working directory of this file system.
virtual std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output) const
Gets real path of Path e.g.
The file should be opened in text mode on platforms that make this distinction.
Definition: FileSystem.h:767
LLVM_NODISCARD std::string upper() const
Convert the given ASCII string to uppercase.
Definition: StringRef.cpp:115
FileCollector(std::string Root, std::string OverlayRoot)
std::error_code writeMapping(StringRef mapping_file)
Write the yaml mapping (for the VFS) to the given file.
std::error_code copy_file(const Twine &From, const Twine &To)
Copy the contents of From to To.
Definition: Path.cpp:964
std::error_code real_path(const Twine &path, SmallVectorImpl< char > &output, bool expand_tilde=false)
Collapse all .
virtual std::error_code isLocal(const Twine &Path, bool &Result)
Is the file mounted on a local filesystem?
vfs::YAMLVFSWriter VFSWriter
The yaml mapping writer.
Definition: FileCollector.h:71
void swap(SmallVectorImpl &RHS)
Definition: SmallVector.h:668
std::error_code status(const Twine &path, file_status &result, bool follow=true)
Get file status as if by POSIX stat().
virtual llvm::ErrorOr< Status > status(const Twine &Path)=0
Get the status of the entry at Path, if one exists.
TimePoint getLastModificationTime() const
The file modification time as reported from the underlying file system.
virtual std::error_code setCurrentWorkingDirectory(const Twine &Path)=0
Set the working directory.
void addFile(const Twine &file)
std::string Root
The root directory where files are copied.
Definition: FileCollector.h:62
StringRef parent_path(StringRef path, Style style=Style::native)
Get parent path.
Definition: Path.cpp:466
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...
Definition: FileSystem.h:1032
size_t size() const
Definition: SmallVector.h:52
A smart pointer to a reference-counted object that inherits from RefCountedBase or ThreadSafeRefCount...
static bool isCaseSensitivePath(StringRef Path)
An input iterator over the entries in a virtual path, similar to llvm::sys::fs::directory_iterator.
static IntrusiveRefCntPtr< vfs::FileSystem > createCollectorVFS(IntrusiveRefCntPtr< vfs::FileSystem > BaseFS, std::shared_ptr< FileCollector > Collector)
Create a VFS that collects all the paths that might be looked at by the file system accesses...
bool remove_dots(SmallVectorImpl< char > &path, bool remove_dot_dot=false, Style style=Style::native)
In-place remove any &#39;.
Definition: Path.cpp:716
void setUseExternalNames(bool UseExtNames)
The virtual file system interface.
virtual directory_iterator dir_begin(const Twine &Dir, std::error_code &EC)=0
Get a directory_iterator for Dir.
std::error_code setPermissions(const Twine &Path, perms Permissions)
Set file permissions.
LLVM_NODISCARD bool equals(StringRef RHS) const
equals - Check for string equality, this is more efficient than compare() when the relative ordering ...
Definition: StringRef.h:174
Provides a library for accessing information about this process and other processes on the operating ...
A raw_ostream that writes to a file descriptor.
Definition: raw_ostream.h:384
StringRef filename(StringRef path, Style style=Style::native)
Get filename.
Definition: Path.cpp:565
virtual llvm::ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path)=0
Get a File object for the file at Path, if one exists.
std::string str() const
Return the twine contents as a std::string.
Definition: Twine.cpp:17
StringRef relative_path(StringRef path, Style style=Style::native)
Get relative path.
Definition: Path.cpp:412
static std::error_code SafelyCloseFileDescriptor(int FD)
print Instructions which execute on loop entry
void setOverlayDir(StringRef OverlayDirectory)
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:48
TimePoint getLastAccessedTime() const
The file access time as reported from the underlying file system.
Register Usage Information Collector
iterator end()
Definition: StringMap.h:317