Bug Summary

File:tools/clang/lib/Basic/VirtualFileSystem.cpp
Warning:line 1241, column 14
The left operand of '==' is a garbage value

Annotated Source Code

1//===- VirtualFileSystem.cpp - Virtual File System Layer --------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9// This file implements the VirtualFileSystem interface.
10//===----------------------------------------------------------------------===//
11
12#include "clang/Basic/VirtualFileSystem.h"
13#include "clang/Basic/FileManager.h"
14#include "llvm/ADT/DenseMap.h"
15#include "llvm/ADT/STLExtras.h"
16#include "llvm/ADT/StringExtras.h"
17#include "llvm/ADT/StringSet.h"
18#include "llvm/ADT/iterator_range.h"
19#include "llvm/Config/llvm-config.h"
20#include "llvm/Support/Debug.h"
21#include "llvm/Support/Errc.h"
22#include "llvm/Support/MemoryBuffer.h"
23#include "llvm/Support/Path.h"
24#include "llvm/Support/Process.h"
25#include "llvm/Support/YAMLParser.h"
26#include <atomic>
27#include <memory>
28#include <utility>
29
30using namespace clang;
31using namespace clang::vfs;
32using namespace llvm;
33using llvm::sys::fs::file_status;
34using llvm::sys::fs::file_type;
35using llvm::sys::fs::perms;
36using llvm::sys::fs::UniqueID;
37
38Status::Status(const file_status &Status)
39 : UID(Status.getUniqueID()), MTime(Status.getLastModificationTime()),
40 User(Status.getUser()), Group(Status.getGroup()), Size(Status.getSize()),
41 Type(Status.type()), Perms(Status.permissions()), IsVFSMapped(false) {}
42
43Status::Status(StringRef Name, UniqueID UID, sys::TimePoint<> MTime,
44 uint32_t User, uint32_t Group, uint64_t Size, file_type Type,
45 perms Perms)
46 : Name(Name), UID(UID), MTime(MTime), User(User), Group(Group), Size(Size),
47 Type(Type), Perms(Perms), IsVFSMapped(false) {}
48
49Status Status::copyWithNewName(const Status &In, StringRef NewName) {
50 return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),
51 In.getUser(), In.getGroup(), In.getSize(), In.getType(),
52 In.getPermissions());
53}
54
55Status Status::copyWithNewName(const file_status &In, StringRef NewName) {
56 return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),
57 In.getUser(), In.getGroup(), In.getSize(), In.type(),
58 In.permissions());
59}
60
61bool Status::equivalent(const Status &Other) const {
62 return getUniqueID() == Other.getUniqueID();
63}
64bool Status::isDirectory() const {
65 return Type == file_type::directory_file;
66}
67bool Status::isRegularFile() const {
68 return Type == file_type::regular_file;
69}
70bool Status::isOther() const {
71 return exists() && !isRegularFile() && !isDirectory() && !isSymlink();
72}
73bool Status::isSymlink() const {
74 return Type == file_type::symlink_file;
75}
76bool Status::isStatusKnown() const {
77 return Type != file_type::status_error;
78}
79bool Status::exists() const {
80 return isStatusKnown() && Type != file_type::file_not_found;
81}
82
83File::~File() {}
84
85FileSystem::~FileSystem() {}
86
87ErrorOr<std::unique_ptr<MemoryBuffer>>
88FileSystem::getBufferForFile(const llvm::Twine &Name, int64_t FileSize,
89 bool RequiresNullTerminator, bool IsVolatile) {
90 auto F = openFileForRead(Name);
91 if (!F)
92 return F.getError();
93
94 return (*F)->getBuffer(Name, FileSize, RequiresNullTerminator, IsVolatile);
95}
96
97std::error_code FileSystem::makeAbsolute(SmallVectorImpl<char> &Path) const {
98 if (llvm::sys::path::is_absolute(Path))
99 return std::error_code();
100
101 auto WorkingDir = getCurrentWorkingDirectory();
102 if (!WorkingDir)
103 return WorkingDir.getError();
104
105 return llvm::sys::fs::make_absolute(WorkingDir.get(), Path);
106}
107
108bool FileSystem::exists(const Twine &Path) {
109 auto Status = status(Path);
110 return Status && Status->exists();
111}
112
113#ifndef NDEBUG
114static bool isTraversalComponent(StringRef Component) {
115 return Component.equals("..") || Component.equals(".");
116}
117
118static bool pathHasTraversal(StringRef Path) {
119 using namespace llvm::sys;
120 for (StringRef Comp : llvm::make_range(path::begin(Path), path::end(Path)))
121 if (isTraversalComponent(Comp))
122 return true;
123 return false;
124}
125#endif
126
127//===-----------------------------------------------------------------------===/
128// RealFileSystem implementation
129//===-----------------------------------------------------------------------===/
130
131namespace {
132/// \brief Wrapper around a raw file descriptor.
133class RealFile : public File {
134 int FD;
135 Status S;
136 std::string RealName;
137 friend class RealFileSystem;
138 RealFile(int FD, StringRef NewName, StringRef NewRealPathName)
139 : FD(FD), S(NewName, {}, {}, {}, {}, {},
140 llvm::sys::fs::file_type::status_error, {}),
141 RealName(NewRealPathName.str()) {
142 assert(FD >= 0 && "Invalid or inactive file descriptor")((FD >= 0 && "Invalid or inactive file descriptor"
) ? static_cast<void> (0) : __assert_fail ("FD >= 0 && \"Invalid or inactive file descriptor\""
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 142, __PRETTY_FUNCTION__))
;
143 }
144
145public:
146 ~RealFile() override;
147 ErrorOr<Status> status() override;
148 ErrorOr<std::string> getName() override;
149 ErrorOr<std::unique_ptr<MemoryBuffer>> getBuffer(const Twine &Name,
150 int64_t FileSize,
151 bool RequiresNullTerminator,
152 bool IsVolatile) override;
153 std::error_code close() override;
154};
155} // end anonymous namespace
156RealFile::~RealFile() { close(); }
157
158ErrorOr<Status> RealFile::status() {
159 assert(FD != -1 && "cannot stat closed file")((FD != -1 && "cannot stat closed file") ? static_cast
<void> (0) : __assert_fail ("FD != -1 && \"cannot stat closed file\""
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 159, __PRETTY_FUNCTION__))
;
160 if (!S.isStatusKnown()) {
161 file_status RealStatus;
162 if (std::error_code EC = sys::fs::status(FD, RealStatus))
163 return EC;
164 S = Status::copyWithNewName(RealStatus, S.getName());
165 }
166 return S;
167}
168
169ErrorOr<std::string> RealFile::getName() {
170 return RealName.empty() ? S.getName().str() : RealName;
171}
172
173ErrorOr<std::unique_ptr<MemoryBuffer>>
174RealFile::getBuffer(const Twine &Name, int64_t FileSize,
175 bool RequiresNullTerminator, bool IsVolatile) {
176 assert(FD != -1 && "cannot get buffer for closed file")((FD != -1 && "cannot get buffer for closed file") ? static_cast
<void> (0) : __assert_fail ("FD != -1 && \"cannot get buffer for closed file\""
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 176, __PRETTY_FUNCTION__))
;
177 return MemoryBuffer::getOpenFile(FD, Name, FileSize, RequiresNullTerminator,
178 IsVolatile);
179}
180
181std::error_code RealFile::close() {
182 std::error_code EC = sys::Process::SafelyCloseFileDescriptor(FD);
183 FD = -1;
184 return EC;
185}
186
187namespace {
188/// \brief The file system according to your operating system.
189class RealFileSystem : public FileSystem {
190public:
191 ErrorOr<Status> status(const Twine &Path) override;
192 ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override;
193 directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
194
195 llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override;
196 std::error_code setCurrentWorkingDirectory(const Twine &Path) override;
197};
198} // end anonymous namespace
199
200ErrorOr<Status> RealFileSystem::status(const Twine &Path) {
201 sys::fs::file_status RealStatus;
202 if (std::error_code EC = sys::fs::status(Path, RealStatus))
203 return EC;
204 return Status::copyWithNewName(RealStatus, Path.str());
205}
206
207ErrorOr<std::unique_ptr<File>>
208RealFileSystem::openFileForRead(const Twine &Name) {
209 int FD;
210 SmallString<256> RealName;
211 if (std::error_code EC = sys::fs::openFileForRead(Name, FD, &RealName))
212 return EC;
213 return std::unique_ptr<File>(new RealFile(FD, Name.str(), RealName.str()));
214}
215
216llvm::ErrorOr<std::string> RealFileSystem::getCurrentWorkingDirectory() const {
217 SmallString<256> Dir;
218 if (std::error_code EC = llvm::sys::fs::current_path(Dir))
219 return EC;
220 return Dir.str().str();
221}
222
223std::error_code RealFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
224 // FIXME: chdir is thread hostile; on the other hand, creating the same
225 // behavior as chdir is complex: chdir resolves the path once, thus
226 // guaranteeing that all subsequent relative path operations work
227 // on the same path the original chdir resulted in. This makes a
228 // difference for example on network filesystems, where symlinks might be
229 // switched during runtime of the tool. Fixing this depends on having a
230 // file system abstraction that allows openat() style interactions.
231 return llvm::sys::fs::set_current_path(Path);
232}
233
234IntrusiveRefCntPtr<FileSystem> vfs::getRealFileSystem() {
235 static IntrusiveRefCntPtr<FileSystem> FS = new RealFileSystem();
236 return FS;
237}
238
239namespace {
240class RealFSDirIter : public clang::vfs::detail::DirIterImpl {
241 llvm::sys::fs::directory_iterator Iter;
242public:
243 RealFSDirIter(const Twine &Path, std::error_code &EC) : Iter(Path, EC) {
244 if (!EC && Iter != llvm::sys::fs::directory_iterator()) {
245 llvm::sys::fs::file_status S;
246 EC = Iter->status(S);
247 CurrentEntry = Status::copyWithNewName(S, Iter->path());
248 }
249 }
250
251 std::error_code increment() override {
252 std::error_code EC;
253 Iter.increment(EC);
254 if (EC) {
255 return EC;
256 } else if (Iter == llvm::sys::fs::directory_iterator()) {
257 CurrentEntry = Status();
258 } else {
259 llvm::sys::fs::file_status S;
260 EC = Iter->status(S);
261 CurrentEntry = Status::copyWithNewName(S, Iter->path());
262 }
263 return EC;
264 }
265};
266}
267
268directory_iterator RealFileSystem::dir_begin(const Twine &Dir,
269 std::error_code &EC) {
270 return directory_iterator(std::make_shared<RealFSDirIter>(Dir, EC));
271}
272
273//===-----------------------------------------------------------------------===/
274// OverlayFileSystem implementation
275//===-----------------------------------------------------------------------===/
276OverlayFileSystem::OverlayFileSystem(IntrusiveRefCntPtr<FileSystem> BaseFS) {
277 FSList.push_back(std::move(BaseFS));
278}
279
280void OverlayFileSystem::pushOverlay(IntrusiveRefCntPtr<FileSystem> FS) {
281 FSList.push_back(FS);
282 // Synchronize added file systems by duplicating the working directory from
283 // the first one in the list.
284 FS->setCurrentWorkingDirectory(getCurrentWorkingDirectory().get());
285}
286
287ErrorOr<Status> OverlayFileSystem::status(const Twine &Path) {
288 // FIXME: handle symlinks that cross file systems
289 for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) {
290 ErrorOr<Status> Status = (*I)->status(Path);
291 if (Status || Status.getError() != llvm::errc::no_such_file_or_directory)
292 return Status;
293 }
294 return make_error_code(llvm::errc::no_such_file_or_directory);
295}
296
297ErrorOr<std::unique_ptr<File>>
298OverlayFileSystem::openFileForRead(const llvm::Twine &Path) {
299 // FIXME: handle symlinks that cross file systems
300 for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) {
301 auto Result = (*I)->openFileForRead(Path);
302 if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
303 return Result;
304 }
305 return make_error_code(llvm::errc::no_such_file_or_directory);
306}
307
308llvm::ErrorOr<std::string>
309OverlayFileSystem::getCurrentWorkingDirectory() const {
310 // All file systems are synchronized, just take the first working directory.
311 return FSList.front()->getCurrentWorkingDirectory();
312}
313std::error_code
314OverlayFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
315 for (auto &FS : FSList)
316 if (std::error_code EC = FS->setCurrentWorkingDirectory(Path))
317 return EC;
318 return std::error_code();
319}
320
321clang::vfs::detail::DirIterImpl::~DirIterImpl() { }
322
323namespace {
324class OverlayFSDirIterImpl : public clang::vfs::detail::DirIterImpl {
325 OverlayFileSystem &Overlays;
326 std::string Path;
327 OverlayFileSystem::iterator CurrentFS;
328 directory_iterator CurrentDirIter;
329 llvm::StringSet<> SeenNames;
330
331 std::error_code incrementFS() {
332 assert(CurrentFS != Overlays.overlays_end() && "incrementing past end")((CurrentFS != Overlays.overlays_end() && "incrementing past end"
) ? static_cast<void> (0) : __assert_fail ("CurrentFS != Overlays.overlays_end() && \"incrementing past end\""
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 332, __PRETTY_FUNCTION__))
;
333 ++CurrentFS;
334 for (auto E = Overlays.overlays_end(); CurrentFS != E; ++CurrentFS) {
335 std::error_code EC;
336 CurrentDirIter = (*CurrentFS)->dir_begin(Path, EC);
337 if (EC && EC != errc::no_such_file_or_directory)
338 return EC;
339 if (CurrentDirIter != directory_iterator())
340 break; // found
341 }
342 return std::error_code();
343 }
344
345 std::error_code incrementDirIter(bool IsFirstTime) {
346 assert((IsFirstTime || CurrentDirIter != directory_iterator()) &&(((IsFirstTime || CurrentDirIter != directory_iterator()) &&
"incrementing past end") ? static_cast<void> (0) : __assert_fail
("(IsFirstTime || CurrentDirIter != directory_iterator()) && \"incrementing past end\""
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 347, __PRETTY_FUNCTION__))
347 "incrementing past end")(((IsFirstTime || CurrentDirIter != directory_iterator()) &&
"incrementing past end") ? static_cast<void> (0) : __assert_fail
("(IsFirstTime || CurrentDirIter != directory_iterator()) && \"incrementing past end\""
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 347, __PRETTY_FUNCTION__))
;
348 std::error_code EC;
349 if (!IsFirstTime)
350 CurrentDirIter.increment(EC);
351 if (!EC && CurrentDirIter == directory_iterator())
352 EC = incrementFS();
353 return EC;
354 }
355
356 std::error_code incrementImpl(bool IsFirstTime) {
357 while (true) {
358 std::error_code EC = incrementDirIter(IsFirstTime);
359 if (EC || CurrentDirIter == directory_iterator()) {
360 CurrentEntry = Status();
361 return EC;
362 }
363 CurrentEntry = *CurrentDirIter;
364 StringRef Name = llvm::sys::path::filename(CurrentEntry.getName());
365 if (SeenNames.insert(Name).second)
366 return EC; // name not seen before
367 }
368 llvm_unreachable("returned above")::llvm::llvm_unreachable_internal("returned above", "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 368)
;
369 }
370
371public:
372 OverlayFSDirIterImpl(const Twine &Path, OverlayFileSystem &FS,
373 std::error_code &EC)
374 : Overlays(FS), Path(Path.str()), CurrentFS(Overlays.overlays_begin()) {
375 CurrentDirIter = (*CurrentFS)->dir_begin(Path, EC);
376 EC = incrementImpl(true);
377 }
378
379 std::error_code increment() override { return incrementImpl(false); }
380};
381} // end anonymous namespace
382
383directory_iterator OverlayFileSystem::dir_begin(const Twine &Dir,
384 std::error_code &EC) {
385 return directory_iterator(
386 std::make_shared<OverlayFSDirIterImpl>(Dir, *this, EC));
387}
388
389namespace clang {
390namespace vfs {
391namespace detail {
392
393enum InMemoryNodeKind { IME_File, IME_Directory };
394
395/// The in memory file system is a tree of Nodes. Every node can either be a
396/// file or a directory.
397class InMemoryNode {
398 Status Stat;
399 InMemoryNodeKind Kind;
400
401public:
402 InMemoryNode(Status Stat, InMemoryNodeKind Kind)
403 : Stat(std::move(Stat)), Kind(Kind) {}
404 virtual ~InMemoryNode() {}
405 const Status &getStatus() const { return Stat; }
406 InMemoryNodeKind getKind() const { return Kind; }
407 virtual std::string toString(unsigned Indent) const = 0;
408};
409
410namespace {
411class InMemoryFile : public InMemoryNode {
412 std::unique_ptr<llvm::MemoryBuffer> Buffer;
413
414public:
415 InMemoryFile(Status Stat, std::unique_ptr<llvm::MemoryBuffer> Buffer)
416 : InMemoryNode(std::move(Stat), IME_File), Buffer(std::move(Buffer)) {}
417
418 llvm::MemoryBuffer *getBuffer() { return Buffer.get(); }
419 std::string toString(unsigned Indent) const override {
420 return (std::string(Indent, ' ') + getStatus().getName() + "\n").str();
421 }
422 static bool classof(const InMemoryNode *N) {
423 return N->getKind() == IME_File;
424 }
425};
426
427/// Adapt a InMemoryFile for VFS' File interface.
428class InMemoryFileAdaptor : public File {
429 InMemoryFile &Node;
430
431public:
432 explicit InMemoryFileAdaptor(InMemoryFile &Node) : Node(Node) {}
433
434 llvm::ErrorOr<Status> status() override { return Node.getStatus(); }
435 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
436 getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
437 bool IsVolatile) override {
438 llvm::MemoryBuffer *Buf = Node.getBuffer();
439 return llvm::MemoryBuffer::getMemBuffer(
440 Buf->getBuffer(), Buf->getBufferIdentifier(), RequiresNullTerminator);
441 }
442 std::error_code close() override { return std::error_code(); }
443};
444} // end anonymous namespace
445
446class InMemoryDirectory : public InMemoryNode {
447 std::map<std::string, std::unique_ptr<InMemoryNode>> Entries;
448
449public:
450 InMemoryDirectory(Status Stat)
451 : InMemoryNode(std::move(Stat), IME_Directory) {}
452 InMemoryNode *getChild(StringRef Name) {
453 auto I = Entries.find(Name);
454 if (I != Entries.end())
455 return I->second.get();
456 return nullptr;
457 }
458 InMemoryNode *addChild(StringRef Name, std::unique_ptr<InMemoryNode> Child) {
459 return Entries.insert(make_pair(Name, std::move(Child)))
460 .first->second.get();
461 }
462
463 typedef decltype(Entries)::const_iterator const_iterator;
464 const_iterator begin() const { return Entries.begin(); }
465 const_iterator end() const { return Entries.end(); }
466
467 std::string toString(unsigned Indent) const override {
468 std::string Result =
469 (std::string(Indent, ' ') + getStatus().getName() + "\n").str();
470 for (const auto &Entry : Entries) {
471 Result += Entry.second->toString(Indent + 2);
472 }
473 return Result;
474 }
475 static bool classof(const InMemoryNode *N) {
476 return N->getKind() == IME_Directory;
477 }
478};
479}
480
481InMemoryFileSystem::InMemoryFileSystem(bool UseNormalizedPaths)
482 : Root(new detail::InMemoryDirectory(
483 Status("", getNextVirtualUniqueID(), llvm::sys::TimePoint<>(), 0, 0,
484 0, llvm::sys::fs::file_type::directory_file,
485 llvm::sys::fs::perms::all_all))),
486 UseNormalizedPaths(UseNormalizedPaths) {}
487
488InMemoryFileSystem::~InMemoryFileSystem() {}
489
490std::string InMemoryFileSystem::toString() const {
491 return Root->toString(/*Indent=*/0);
492}
493
494bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime,
495 std::unique_ptr<llvm::MemoryBuffer> Buffer) {
496 SmallString<128> Path;
497 P.toVector(Path);
498
499 // Fix up relative paths. This just prepends the current working directory.
500 std::error_code EC = makeAbsolute(Path);
501 assert(!EC)((!EC) ? static_cast<void> (0) : __assert_fail ("!EC", "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 501, __PRETTY_FUNCTION__))
;
502 (void)EC;
503
504 if (useNormalizedPaths())
505 llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
506
507 if (Path.empty())
508 return false;
509
510 detail::InMemoryDirectory *Dir = Root.get();
511 auto I = llvm::sys::path::begin(Path), E = llvm::sys::path::end(Path);
512 while (true) {
513 StringRef Name = *I;
514 detail::InMemoryNode *Node = Dir->getChild(Name);
515 ++I;
516 if (!Node) {
517 if (I == E) {
518 // End of the path, create a new file.
519 // FIXME: expose the status details in the interface.
520 Status Stat(P.str(), getNextVirtualUniqueID(),
521 llvm::sys::toTimePoint(ModificationTime), 0, 0,
522 Buffer->getBufferSize(),
523 llvm::sys::fs::file_type::regular_file,
524 llvm::sys::fs::all_all);
525 Dir->addChild(Name, llvm::make_unique<detail::InMemoryFile>(
526 std::move(Stat), std::move(Buffer)));
527 return true;
528 }
529
530 // Create a new directory. Use the path up to here.
531 // FIXME: expose the status details in the interface.
532 Status Stat(
533 StringRef(Path.str().begin(), Name.end() - Path.str().begin()),
534 getNextVirtualUniqueID(), llvm::sys::toTimePoint(ModificationTime), 0,
535 0, Buffer->getBufferSize(), llvm::sys::fs::file_type::directory_file,
536 llvm::sys::fs::all_all);
537 Dir = cast<detail::InMemoryDirectory>(Dir->addChild(
538 Name, llvm::make_unique<detail::InMemoryDirectory>(std::move(Stat))));
539 continue;
540 }
541
542 if (auto *NewDir = dyn_cast<detail::InMemoryDirectory>(Node)) {
543 Dir = NewDir;
544 } else {
545 assert(isa<detail::InMemoryFile>(Node) &&((isa<detail::InMemoryFile>(Node) && "Must be either file or directory!"
) ? static_cast<void> (0) : __assert_fail ("isa<detail::InMemoryFile>(Node) && \"Must be either file or directory!\""
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 546, __PRETTY_FUNCTION__))
546 "Must be either file or directory!")((isa<detail::InMemoryFile>(Node) && "Must be either file or directory!"
) ? static_cast<void> (0) : __assert_fail ("isa<detail::InMemoryFile>(Node) && \"Must be either file or directory!\""
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 546, __PRETTY_FUNCTION__))
;
547
548 // Trying to insert a directory in place of a file.
549 if (I != E)
550 return false;
551
552 // Return false only if the new file is different from the existing one.
553 return cast<detail::InMemoryFile>(Node)->getBuffer()->getBuffer() ==
554 Buffer->getBuffer();
555 }
556 }
557}
558
559bool InMemoryFileSystem::addFileNoOwn(const Twine &P, time_t ModificationTime,
560 llvm::MemoryBuffer *Buffer) {
561 return addFile(P, ModificationTime,
562 llvm::MemoryBuffer::getMemBuffer(
563 Buffer->getBuffer(), Buffer->getBufferIdentifier()));
564}
565
566static ErrorOr<detail::InMemoryNode *>
567lookupInMemoryNode(const InMemoryFileSystem &FS, detail::InMemoryDirectory *Dir,
568 const Twine &P) {
569 SmallString<128> Path;
570 P.toVector(Path);
571
572 // Fix up relative paths. This just prepends the current working directory.
573 std::error_code EC = FS.makeAbsolute(Path);
574 assert(!EC)((!EC) ? static_cast<void> (0) : __assert_fail ("!EC", "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 574, __PRETTY_FUNCTION__))
;
575 (void)EC;
576
577 if (FS.useNormalizedPaths())
578 llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
579
580 if (Path.empty())
581 return Dir;
582
583 auto I = llvm::sys::path::begin(Path), E = llvm::sys::path::end(Path);
584 while (true) {
585 detail::InMemoryNode *Node = Dir->getChild(*I);
586 ++I;
587 if (!Node)
588 return errc::no_such_file_or_directory;
589
590 // Return the file if it's at the end of the path.
591 if (auto File = dyn_cast<detail::InMemoryFile>(Node)) {
592 if (I == E)
593 return File;
594 return errc::no_such_file_or_directory;
595 }
596
597 // Traverse directories.
598 Dir = cast<detail::InMemoryDirectory>(Node);
599 if (I == E)
600 return Dir;
601 }
602}
603
604llvm::ErrorOr<Status> InMemoryFileSystem::status(const Twine &Path) {
605 auto Node = lookupInMemoryNode(*this, Root.get(), Path);
606 if (Node)
607 return (*Node)->getStatus();
608 return Node.getError();
609}
610
611llvm::ErrorOr<std::unique_ptr<File>>
612InMemoryFileSystem::openFileForRead(const Twine &Path) {
613 auto Node = lookupInMemoryNode(*this, Root.get(), Path);
614 if (!Node)
615 return Node.getError();
616
617 // When we have a file provide a heap-allocated wrapper for the memory buffer
618 // to match the ownership semantics for File.
619 if (auto *F = dyn_cast<detail::InMemoryFile>(*Node))
620 return std::unique_ptr<File>(new detail::InMemoryFileAdaptor(*F));
621
622 // FIXME: errc::not_a_file?
623 return make_error_code(llvm::errc::invalid_argument);
624}
625
626namespace {
627/// Adaptor from InMemoryDir::iterator to directory_iterator.
628class InMemoryDirIterator : public clang::vfs::detail::DirIterImpl {
629 detail::InMemoryDirectory::const_iterator I;
630 detail::InMemoryDirectory::const_iterator E;
631
632public:
633 InMemoryDirIterator() {}
634 explicit InMemoryDirIterator(detail::InMemoryDirectory &Dir)
635 : I(Dir.begin()), E(Dir.end()) {
636 if (I != E)
637 CurrentEntry = I->second->getStatus();
638 }
639
640 std::error_code increment() override {
641 ++I;
642 // When we're at the end, make CurrentEntry invalid and DirIterImpl will do
643 // the rest.
644 CurrentEntry = I != E ? I->second->getStatus() : Status();
645 return std::error_code();
646 }
647};
648} // end anonymous namespace
649
650directory_iterator InMemoryFileSystem::dir_begin(const Twine &Dir,
651 std::error_code &EC) {
652 auto Node = lookupInMemoryNode(*this, Root.get(), Dir);
653 if (!Node) {
654 EC = Node.getError();
655 return directory_iterator(std::make_shared<InMemoryDirIterator>());
656 }
657
658 if (auto *DirNode = dyn_cast<detail::InMemoryDirectory>(*Node))
659 return directory_iterator(std::make_shared<InMemoryDirIterator>(*DirNode));
660
661 EC = make_error_code(llvm::errc::not_a_directory);
662 return directory_iterator(std::make_shared<InMemoryDirIterator>());
663}
664
665std::error_code InMemoryFileSystem::setCurrentWorkingDirectory(const Twine &P) {
666 SmallString<128> Path;
667 P.toVector(Path);
668
669 // Fix up relative paths. This just prepends the current working directory.
670 std::error_code EC = makeAbsolute(Path);
671 assert(!EC)((!EC) ? static_cast<void> (0) : __assert_fail ("!EC", "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 671, __PRETTY_FUNCTION__))
;
672 (void)EC;
673
674 if (useNormalizedPaths())
675 llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
676
677 if (!Path.empty())
678 WorkingDirectory = Path.str();
679 return std::error_code();
680}
681}
682}
683
684//===-----------------------------------------------------------------------===/
685// RedirectingFileSystem implementation
686//===-----------------------------------------------------------------------===/
687
688namespace {
689
690enum EntryKind {
691 EK_Directory,
692 EK_File
693};
694
695/// \brief A single file or directory in the VFS.
696class Entry {
697 EntryKind Kind;
698 std::string Name;
699
700public:
701 virtual ~Entry();
702 Entry(EntryKind K, StringRef Name) : Kind(K), Name(Name) {}
703 StringRef getName() const { return Name; }
704 EntryKind getKind() const { return Kind; }
705};
706
707class RedirectingDirectoryEntry : public Entry {
708 std::vector<std::unique_ptr<Entry>> Contents;
709 Status S;
710
711public:
712 RedirectingDirectoryEntry(StringRef Name,
713 std::vector<std::unique_ptr<Entry>> Contents,
714 Status S)
715 : Entry(EK_Directory, Name), Contents(std::move(Contents)),
716 S(std::move(S)) {}
717 RedirectingDirectoryEntry(StringRef Name, Status S)
718 : Entry(EK_Directory, Name), S(std::move(S)) {}
719 Status getStatus() { return S; }
720 void addContent(std::unique_ptr<Entry> Content) {
721 Contents.push_back(std::move(Content));
722 }
723 Entry *getLastContent() const { return Contents.back().get(); }
724 typedef decltype(Contents)::iterator iterator;
725 iterator contents_begin() { return Contents.begin(); }
726 iterator contents_end() { return Contents.end(); }
727 static bool classof(const Entry *E) { return E->getKind() == EK_Directory; }
728};
729
730class RedirectingFileEntry : public Entry {
731public:
732 enum NameKind {
733 NK_NotSet,
734 NK_External,
735 NK_Virtual
736 };
737private:
738 std::string ExternalContentsPath;
739 NameKind UseName;
740public:
741 RedirectingFileEntry(StringRef Name, StringRef ExternalContentsPath,
742 NameKind UseName)
743 : Entry(EK_File, Name), ExternalContentsPath(ExternalContentsPath),
744 UseName(UseName) {}
745 StringRef getExternalContentsPath() const { return ExternalContentsPath; }
746 /// \brief whether to use the external path as the name for this file.
747 bool useExternalName(bool GlobalUseExternalName) const {
748 return UseName == NK_NotSet ? GlobalUseExternalName
749 : (UseName == NK_External);
750 }
751 NameKind getUseName() const { return UseName; }
752 static bool classof(const Entry *E) { return E->getKind() == EK_File; }
753};
754
755class RedirectingFileSystem;
756
757class VFSFromYamlDirIterImpl : public clang::vfs::detail::DirIterImpl {
758 std::string Dir;
759 RedirectingFileSystem &FS;
760 RedirectingDirectoryEntry::iterator Current, End;
761
762public:
763 VFSFromYamlDirIterImpl(const Twine &Path, RedirectingFileSystem &FS,
764 RedirectingDirectoryEntry::iterator Begin,
765 RedirectingDirectoryEntry::iterator End,
766 std::error_code &EC);
767 std::error_code increment() override;
768};
769
770/// \brief A virtual file system parsed from a YAML file.
771///
772/// Currently, this class allows creating virtual directories and mapping
773/// virtual file paths to existing external files, available in \c ExternalFS.
774///
775/// The basic structure of the parsed file is:
776/// \verbatim
777/// {
778/// 'version': <version number>,
779/// <optional configuration>
780/// 'roots': [
781/// <directory entries>
782/// ]
783/// }
784/// \endverbatim
785///
786/// All configuration options are optional.
787/// 'case-sensitive': <boolean, default=true>
788/// 'use-external-names': <boolean, default=true>
789/// 'overlay-relative': <boolean, default=false>
790/// 'ignore-non-existent-contents': <boolean, default=true>
791///
792/// Virtual directories are represented as
793/// \verbatim
794/// {
795/// 'type': 'directory',
796/// 'name': <string>,
797/// 'contents': [ <file or directory entries> ]
798/// }
799/// \endverbatim
800///
801/// The default attributes for virtual directories are:
802/// \verbatim
803/// MTime = now() when created
804/// Perms = 0777
805/// User = Group = 0
806/// Size = 0
807/// UniqueID = unspecified unique value
808/// \endverbatim
809///
810/// Re-mapped files are represented as
811/// \verbatim
812/// {
813/// 'type': 'file',
814/// 'name': <string>,
815/// 'use-external-name': <boolean> # Optional
816/// 'external-contents': <path to external file>)
817/// }
818/// \endverbatim
819///
820/// and inherit their attributes from the external contents.
821///
822/// In both cases, the 'name' field may contain multiple path components (e.g.
823/// /path/to/file). However, any directory that contains more than one child
824/// must be uniquely represented by a directory entry.
825class RedirectingFileSystem : public vfs::FileSystem {
826 /// The root(s) of the virtual file system.
827 std::vector<std::unique_ptr<Entry>> Roots;
828 /// \brief The file system to use for external references.
829 IntrusiveRefCntPtr<FileSystem> ExternalFS;
830 /// If IsRelativeOverlay is set, this represents the directory
831 /// path that should be prefixed to each 'external-contents' entry
832 /// when reading from YAML files.
833 std::string ExternalContentsPrefixDir;
834
835 /// @name Configuration
836 /// @{
837
838 /// \brief Whether to perform case-sensitive comparisons.
839 ///
840 /// Currently, case-insensitive matching only works correctly with ASCII.
841 bool CaseSensitive = true;
842
843 /// IsRelativeOverlay marks whether a IsExternalContentsPrefixDir path must
844 /// be prefixed in every 'external-contents' when reading from YAML files.
845 bool IsRelativeOverlay = false;
846
847 /// \brief Whether to use to use the value of 'external-contents' for the
848 /// names of files. This global value is overridable on a per-file basis.
849 bool UseExternalNames = true;
850
851 /// \brief Whether an invalid path obtained via 'external-contents' should
852 /// cause iteration on the VFS to stop. If 'true', the VFS should ignore
853 /// the entry and continue with the next. Allows YAML files to be shared
854 /// across multiple compiler invocations regardless of prior existent
855 /// paths in 'external-contents'. This global value is overridable on a
856 /// per-file basis.
857 bool IgnoreNonExistentContents = true;
858 /// @}
859
860 /// Virtual file paths and external files could be canonicalized without "..",
861 /// "." and "./" in their paths. FIXME: some unittests currently fail on
862 /// win32 when using remove_dots and remove_leading_dotslash on paths.
863 bool UseCanonicalizedPaths =
864#ifdef LLVM_ON_WIN32
865 false;
866#else
867 true;
868#endif
869
870 friend class RedirectingFileSystemParser;
871
872private:
873 RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> ExternalFS)
874 : ExternalFS(std::move(ExternalFS)) {}
875
876 /// \brief Looks up the path <tt>[Start, End)</tt> in \p From, possibly
877 /// recursing into the contents of \p From if it is a directory.
878 ErrorOr<Entry *> lookupPath(sys::path::const_iterator Start,
879 sys::path::const_iterator End, Entry *From);
880
881 /// \brief Get the status of a given an \c Entry.
882 ErrorOr<Status> status(const Twine &Path, Entry *E);
883
884public:
885 /// \brief Looks up \p Path in \c Roots.
886 ErrorOr<Entry *> lookupPath(const Twine &Path);
887
888 /// \brief Parses \p Buffer, which is expected to be in YAML format and
889 /// returns a virtual file system representing its contents.
890 static RedirectingFileSystem *
891 create(std::unique_ptr<MemoryBuffer> Buffer,
892 SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath,
893 void *DiagContext, IntrusiveRefCntPtr<FileSystem> ExternalFS);
894
895 ErrorOr<Status> status(const Twine &Path) override;
896 ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override;
897
898 llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
899 return ExternalFS->getCurrentWorkingDirectory();
900 }
901 std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
902 return ExternalFS->setCurrentWorkingDirectory(Path);
903 }
904
905 directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override{
906 ErrorOr<Entry *> E = lookupPath(Dir);
907 if (!E) {
908 EC = E.getError();
909 return directory_iterator();
910 }
911 ErrorOr<Status> S = status(Dir, *E);
912 if (!S) {
913 EC = S.getError();
914 return directory_iterator();
915 }
916 if (!S->isDirectory()) {
917 EC = std::error_code(static_cast<int>(errc::not_a_directory),
918 std::system_category());
919 return directory_iterator();
920 }
921
922 auto *D = cast<RedirectingDirectoryEntry>(*E);
923 return directory_iterator(std::make_shared<VFSFromYamlDirIterImpl>(Dir,
924 *this, D->contents_begin(), D->contents_end(), EC));
925 }
926
927 void setExternalContentsPrefixDir(StringRef PrefixDir) {
928 ExternalContentsPrefixDir = PrefixDir.str();
929 }
930
931 StringRef getExternalContentsPrefixDir() const {
932 return ExternalContentsPrefixDir;
933 }
934
935 bool ignoreNonExistentContents() const {
936 return IgnoreNonExistentContents;
937 }
938
939#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
940LLVM_DUMP_METHOD__attribute__((noinline)) __attribute__((__used__)) void dump() const {
941 for (const std::unique_ptr<Entry> &Root : Roots)
942 dumpEntry(Root.get());
943 }
944
945LLVM_DUMP_METHOD__attribute__((noinline)) __attribute__((__used__)) void dumpEntry(Entry *E, int NumSpaces = 0) const {
946 StringRef Name = E->getName();
947 for (int i = 0, e = NumSpaces; i < e; ++i)
948 dbgs() << " ";
949 dbgs() << "'" << Name.str().c_str() << "'" << "\n";
950
951 if (E->getKind() == EK_Directory) {
952 auto *DE = dyn_cast<RedirectingDirectoryEntry>(E);
953 assert(DE && "Should be a directory")((DE && "Should be a directory") ? static_cast<void
> (0) : __assert_fail ("DE && \"Should be a directory\""
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 953, __PRETTY_FUNCTION__))
;
954
955 for (std::unique_ptr<Entry> &SubEntry :
956 llvm::make_range(DE->contents_begin(), DE->contents_end()))
957 dumpEntry(SubEntry.get(), NumSpaces+2);
958 }
959 }
960#endif
961
962};
963
964/// \brief A helper class to hold the common YAML parsing state.
965class RedirectingFileSystemParser {
966 yaml::Stream &Stream;
967
968 void error(yaml::Node *N, const Twine &Msg) {
969 Stream.printError(N, Msg);
970 }
971
972 // false on error
973 bool parseScalarString(yaml::Node *N, StringRef &Result,
974 SmallVectorImpl<char> &Storage) {
975 yaml::ScalarNode *S = dyn_cast<yaml::ScalarNode>(N);
976 if (!S) {
977 error(N, "expected string");
978 return false;
979 }
980 Result = S->getValue(Storage);
981 return true;
982 }
983
984 // false on error
985 bool parseScalarBool(yaml::Node *N, bool &Result) {
986 SmallString<5> Storage;
987 StringRef Value;
988 if (!parseScalarString(N, Value, Storage))
989 return false;
990
991 if (Value.equals_lower("true") || Value.equals_lower("on") ||
992 Value.equals_lower("yes") || Value == "1") {
993 Result = true;
994 return true;
995 } else if (Value.equals_lower("false") || Value.equals_lower("off") ||
996 Value.equals_lower("no") || Value == "0") {
997 Result = false;
998 return true;
999 }
1000
1001 error(N, "expected boolean value");
1002 return false;
1003 }
1004
1005 struct KeyStatus {
1006 KeyStatus(bool Required=false) : Required(Required), Seen(false) {}
1007 bool Required;
1008 bool Seen;
1009 };
1010 typedef std::pair<StringRef, KeyStatus> KeyStatusPair;
1011
1012 // false on error
1013 bool checkDuplicateOrUnknownKey(yaml::Node *KeyNode, StringRef Key,
1014 DenseMap<StringRef, KeyStatus> &Keys) {
1015 if (!Keys.count(Key)) {
1016 error(KeyNode, "unknown key");
1017 return false;
1018 }
1019 KeyStatus &S = Keys[Key];
1020 if (S.Seen) {
1021 error(KeyNode, Twine("duplicate key '") + Key + "'");
1022 return false;
1023 }
1024 S.Seen = true;
1025 return true;
1026 }
1027
1028 // false on error
1029 bool checkMissingKeys(yaml::Node *Obj, DenseMap<StringRef, KeyStatus> &Keys) {
1030 for (DenseMap<StringRef, KeyStatus>::iterator I = Keys.begin(),
1031 E = Keys.end();
1032 I != E; ++I) {
1033 if (I->second.Required && !I->second.Seen) {
1034 error(Obj, Twine("missing key '") + I->first + "'");
1035 return false;
1036 }
1037 }
1038 return true;
1039 }
1040
1041 Entry *lookupOrCreateEntry(RedirectingFileSystem *FS, StringRef Name,
1042 Entry *ParentEntry = nullptr) {
1043 if (!ParentEntry) { // Look for a existent root
1044 for (const std::unique_ptr<Entry> &Root : FS->Roots) {
1045 if (Name.equals(Root->getName())) {
1046 ParentEntry = Root.get();
1047 return ParentEntry;
1048 }
1049 }
1050 } else { // Advance to the next component
1051 auto *DE = dyn_cast<RedirectingDirectoryEntry>(ParentEntry);
1052 for (std::unique_ptr<Entry> &Content :
1053 llvm::make_range(DE->contents_begin(), DE->contents_end())) {
1054 auto *DirContent = dyn_cast<RedirectingDirectoryEntry>(Content.get());
1055 if (DirContent && Name.equals(Content->getName()))
1056 return DirContent;
1057 }
1058 }
1059
1060 // ... or create a new one
1061 std::unique_ptr<Entry> E = llvm::make_unique<RedirectingDirectoryEntry>(
1062 Name,
1063 Status("", getNextVirtualUniqueID(), std::chrono::system_clock::now(),
1064 0, 0, 0, file_type::directory_file, sys::fs::all_all));
1065
1066 if (!ParentEntry) { // Add a new root to the overlay
1067 FS->Roots.push_back(std::move(E));
1068 ParentEntry = FS->Roots.back().get();
1069 return ParentEntry;
1070 }
1071
1072 auto *DE = dyn_cast<RedirectingDirectoryEntry>(ParentEntry);
1073 DE->addContent(std::move(E));
1074 return DE->getLastContent();
1075 }
1076
1077 void uniqueOverlayTree(RedirectingFileSystem *FS, Entry *SrcE,
1078 Entry *NewParentE = nullptr) {
1079 StringRef Name = SrcE->getName();
1080 switch (SrcE->getKind()) {
1081 case EK_Directory: {
1082 auto *DE = dyn_cast<RedirectingDirectoryEntry>(SrcE);
1083 assert(DE && "Must be a directory")((DE && "Must be a directory") ? static_cast<void>
(0) : __assert_fail ("DE && \"Must be a directory\""
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 1083, __PRETTY_FUNCTION__))
;
1084 // Empty directories could be present in the YAML as a way to
1085 // describe a file for a current directory after some of its subdir
1086 // is parsed. This only leads to redundant walks, ignore it.
1087 if (!Name.empty())
1088 NewParentE = lookupOrCreateEntry(FS, Name, NewParentE);
1089 for (std::unique_ptr<Entry> &SubEntry :
1090 llvm::make_range(DE->contents_begin(), DE->contents_end()))
1091 uniqueOverlayTree(FS, SubEntry.get(), NewParentE);
1092 break;
1093 }
1094 case EK_File: {
1095 auto *FE = dyn_cast<RedirectingFileEntry>(SrcE);
1096 assert(FE && "Must be a file")((FE && "Must be a file") ? static_cast<void> (
0) : __assert_fail ("FE && \"Must be a file\"", "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 1096, __PRETTY_FUNCTION__))
;
1097 assert(NewParentE && "Parent entry must exist")((NewParentE && "Parent entry must exist") ? static_cast
<void> (0) : __assert_fail ("NewParentE && \"Parent entry must exist\""
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 1097, __PRETTY_FUNCTION__))
;
1098 auto *DE = dyn_cast<RedirectingDirectoryEntry>(NewParentE);
1099 DE->addContent(llvm::make_unique<RedirectingFileEntry>(
1100 Name, FE->getExternalContentsPath(), FE->getUseName()));
1101 break;
1102 }
1103 }
1104 }
1105
1106 std::unique_ptr<Entry> parseEntry(yaml::Node *N, RedirectingFileSystem *FS) {
1107 yaml::MappingNode *M = dyn_cast<yaml::MappingNode>(N);
1108 if (!M) {
1
Assuming 'M' is non-null
2
Taking false branch
1109 error(N, "expected mapping node for file or directory entry");
1110 return nullptr;
1111 }
1112
1113 KeyStatusPair Fields[] = {
1114 KeyStatusPair("name", true),
1115 KeyStatusPair("type", true),
1116 KeyStatusPair("contents", false),
1117 KeyStatusPair("external-contents", false),
1118 KeyStatusPair("use-external-name", false),
1119 };
1120
1121 DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields));
1122
1123 bool HasContents = false; // external or otherwise
1124 std::vector<std::unique_ptr<Entry>> EntryArrayContents;
1125 std::string ExternalContentsPath;
1126 std::string Name;
1127 auto UseExternalName = RedirectingFileEntry::NK_NotSet;
1128 EntryKind Kind;
3
'Kind' declared without an initial value
1129
1130 for (yaml::MappingNode::iterator I = M->begin(), E = M->end(); I != E;
4
Loop condition is true. Entering loop body
19
Loop condition is true. Entering loop body
34
Loop condition is true. Entering loop body
47
Loop condition is false. Execution continues on line 1229
1131 ++I) {
1132 StringRef Key;
1133 // Reuse the buffer for key and value, since we don't look at key after
1134 // parsing value.
1135 SmallString<256> Buffer;
1136 if (!parseScalarString(I->getKey(), Key, Buffer))
5
Taking false branch
20
Taking false branch
35
Taking false branch
1137 return nullptr;
1138
1139 if (!checkDuplicateOrUnknownKey(I->getKey(), Key, Keys))
6
Taking false branch
21
Taking false branch
36
Taking false branch
1140 return nullptr;
1141
1142 StringRef Value;
1143 if (Key == "name") {
7
Assuming the condition is false
8
Taking false branch
22
Assuming the condition is false
23
Taking false branch
37
Assuming the condition is false
38
Taking false branch
1144 if (!parseScalarString(I->getValue(), Value, Buffer))
1145 return nullptr;
1146
1147 if (FS->UseCanonicalizedPaths) {
1148 SmallString<256> Path(Value);
1149 // Guarantee that old YAML files containing paths with ".." and "."
1150 // are properly canonicalized before read into the VFS.
1151 Path = sys::path::remove_leading_dotslash(Path);
1152 sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
1153 Name = Path.str();
1154 } else {
1155 Name = Value;
1156 }
1157 } else if (Key == "type") {
9
Assuming the condition is false
10
Taking false branch
24
Assuming the condition is false
25
Taking false branch
39
Assuming the condition is false
40
Taking false branch
1158 if (!parseScalarString(I->getValue(), Value, Buffer))
1159 return nullptr;
1160 if (Value == "file")
1161 Kind = EK_File;
1162 else if (Value == "directory")
1163 Kind = EK_Directory;
1164 else {
1165 error(I->getValue(), "unknown value for 'type'");
1166 return nullptr;
1167 }
1168 } else if (Key == "contents") {
11
Assuming the condition is false
12
Taking false branch
26
Assuming the condition is false
27
Taking false branch
41
Assuming the condition is true
42
Taking true branch
1169 if (HasContents) {
43
Taking false branch
1170 error(I->getKey(),
1171 "entry already has 'contents' or 'external-contents'");
1172 return nullptr;
1173 }
1174 HasContents = true;
1175 yaml::SequenceNode *Contents =
1176 dyn_cast<yaml::SequenceNode>(I->getValue());
1177 if (!Contents) {
44
Assuming 'Contents' is non-null
45
Taking false branch
1178 // FIXME: this is only for directories, what about files?
1179 error(I->getValue(), "expected array");
1180 return nullptr;
1181 }
1182
1183 for (yaml::SequenceNode::iterator I = Contents->begin(),
46
Loop condition is false. Execution continues on line 1131
1184 E = Contents->end();
1185 I != E; ++I) {
1186 if (std::unique_ptr<Entry> E = parseEntry(&*I, FS))
1187 EntryArrayContents.push_back(std::move(E));
1188 else
1189 return nullptr;
1190 }
1191 } else if (Key == "external-contents") {
13
Assuming the condition is false
14
Taking false branch
28
Assuming the condition is false
29
Taking false branch
1192 if (HasContents) {
1193 error(I->getKey(),
1194 "entry already has 'contents' or 'external-contents'");
1195 return nullptr;
1196 }
1197 HasContents = true;
1198 if (!parseScalarString(I->getValue(), Value, Buffer))
1199 return nullptr;
1200
1201 SmallString<256> FullPath;
1202 if (FS->IsRelativeOverlay) {
1203 FullPath = FS->getExternalContentsPrefixDir();
1204 assert(!FullPath.empty() &&((!FullPath.empty() && "External contents prefix directory must exist"
) ? static_cast<void> (0) : __assert_fail ("!FullPath.empty() && \"External contents prefix directory must exist\""
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 1205, __PRETTY_FUNCTION__))
1205 "External contents prefix directory must exist")((!FullPath.empty() && "External contents prefix directory must exist"
) ? static_cast<void> (0) : __assert_fail ("!FullPath.empty() && \"External contents prefix directory must exist\""
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 1205, __PRETTY_FUNCTION__))
;
1206 llvm::sys::path::append(FullPath, Value);
1207 } else {
1208 FullPath = Value;
1209 }
1210
1211 if (FS->UseCanonicalizedPaths) {
1212 // Guarantee that old YAML files containing paths with ".." and "."
1213 // are properly canonicalized before read into the VFS.
1214 FullPath = sys::path::remove_leading_dotslash(FullPath);
1215 sys::path::remove_dots(FullPath, /*remove_dot_dot=*/true);
1216 }
1217 ExternalContentsPath = FullPath.str();
1218 } else if (Key == "use-external-name") {
15
Assuming the condition is true
16
Taking true branch
30
Assuming the condition is true
31
Taking true branch
1219 bool Val;
1220 if (!parseScalarBool(I->getValue(), Val))
17
Taking false branch
32
Taking false branch
1221 return nullptr;
1222 UseExternalName = Val ? RedirectingFileEntry::NK_External
18
'?' condition is false
33
'?' condition is false
1223 : RedirectingFileEntry::NK_Virtual;
1224 } else {
1225 llvm_unreachable("key missing from Keys")::llvm::llvm_unreachable_internal("key missing from Keys", "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 1225)
;
1226 }
1227 }
1228
1229 if (Stream.failed())
48
Assuming the condition is false
49
Taking false branch
1230 return nullptr;
1231
1232 // check for missing keys
1233 if (!HasContents) {
50
Taking false branch
1234 error(N, "missing key 'contents' or 'external-contents'");
1235 return nullptr;
1236 }
1237 if (!checkMissingKeys(N, Keys))
51
Assuming the condition is false
52
Taking false branch
1238 return nullptr;
1239
1240 // check invalid configuration
1241 if (Kind == EK_Directory &&
53
The left operand of '==' is a garbage value
1242 UseExternalName != RedirectingFileEntry::NK_NotSet) {
1243 error(N, "'use-external-name' is not supported for directories");
1244 return nullptr;
1245 }
1246
1247 // Remove trailing slash(es), being careful not to remove the root path
1248 StringRef Trimmed(Name);
1249 size_t RootPathLen = sys::path::root_path(Trimmed).size();
1250 while (Trimmed.size() > RootPathLen &&
1251 sys::path::is_separator(Trimmed.back()))
1252 Trimmed = Trimmed.slice(0, Trimmed.size()-1);
1253 // Get the last component
1254 StringRef LastComponent = sys::path::filename(Trimmed);
1255
1256 std::unique_ptr<Entry> Result;
1257 switch (Kind) {
1258 case EK_File:
1259 Result = llvm::make_unique<RedirectingFileEntry>(
1260 LastComponent, std::move(ExternalContentsPath), UseExternalName);
1261 break;
1262 case EK_Directory:
1263 Result = llvm::make_unique<RedirectingDirectoryEntry>(
1264 LastComponent, std::move(EntryArrayContents),
1265 Status("", getNextVirtualUniqueID(), std::chrono::system_clock::now(),
1266 0, 0, 0, file_type::directory_file, sys::fs::all_all));
1267 break;
1268 }
1269
1270 StringRef Parent = sys::path::parent_path(Trimmed);
1271 if (Parent.empty())
1272 return Result;
1273
1274 // if 'name' contains multiple components, create implicit directory entries
1275 for (sys::path::reverse_iterator I = sys::path::rbegin(Parent),
1276 E = sys::path::rend(Parent);
1277 I != E; ++I) {
1278 std::vector<std::unique_ptr<Entry>> Entries;
1279 Entries.push_back(std::move(Result));
1280 Result = llvm::make_unique<RedirectingDirectoryEntry>(
1281 *I, std::move(Entries),
1282 Status("", getNextVirtualUniqueID(), std::chrono::system_clock::now(),
1283 0, 0, 0, file_type::directory_file, sys::fs::all_all));
1284 }
1285 return Result;
1286 }
1287
1288public:
1289 RedirectingFileSystemParser(yaml::Stream &S) : Stream(S) {}
1290
1291 // false on error
1292 bool parse(yaml::Node *Root, RedirectingFileSystem *FS) {
1293 yaml::MappingNode *Top = dyn_cast<yaml::MappingNode>(Root);
1294 if (!Top) {
1295 error(Root, "expected mapping node");
1296 return false;
1297 }
1298
1299 KeyStatusPair Fields[] = {
1300 KeyStatusPair("version", true),
1301 KeyStatusPair("case-sensitive", false),
1302 KeyStatusPair("use-external-names", false),
1303 KeyStatusPair("overlay-relative", false),
1304 KeyStatusPair("ignore-non-existent-contents", false),
1305 KeyStatusPair("roots", true),
1306 };
1307
1308 DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields));
1309 std::vector<std::unique_ptr<Entry>> RootEntries;
1310
1311 // Parse configuration and 'roots'
1312 for (yaml::MappingNode::iterator I = Top->begin(), E = Top->end(); I != E;
1313 ++I) {
1314 SmallString<10> KeyBuffer;
1315 StringRef Key;
1316 if (!parseScalarString(I->getKey(), Key, KeyBuffer))
1317 return false;
1318
1319 if (!checkDuplicateOrUnknownKey(I->getKey(), Key, Keys))
1320 return false;
1321
1322 if (Key == "roots") {
1323 yaml::SequenceNode *Roots = dyn_cast<yaml::SequenceNode>(I->getValue());
1324 if (!Roots) {
1325 error(I->getValue(), "expected array");
1326 return false;
1327 }
1328
1329 for (yaml::SequenceNode::iterator I = Roots->begin(), E = Roots->end();
1330 I != E; ++I) {
1331 if (std::unique_ptr<Entry> E = parseEntry(&*I, FS))
1332 RootEntries.push_back(std::move(E));
1333 else
1334 return false;
1335 }
1336 } else if (Key == "version") {
1337 StringRef VersionString;
1338 SmallString<4> Storage;
1339 if (!parseScalarString(I->getValue(), VersionString, Storage))
1340 return false;
1341 int Version;
1342 if (VersionString.getAsInteger<int>(10, Version)) {
1343 error(I->getValue(), "expected integer");
1344 return false;
1345 }
1346 if (Version < 0) {
1347 error(I->getValue(), "invalid version number");
1348 return false;
1349 }
1350 if (Version != 0) {
1351 error(I->getValue(), "version mismatch, expected 0");
1352 return false;
1353 }
1354 } else if (Key == "case-sensitive") {
1355 if (!parseScalarBool(I->getValue(), FS->CaseSensitive))
1356 return false;
1357 } else if (Key == "overlay-relative") {
1358 if (!parseScalarBool(I->getValue(), FS->IsRelativeOverlay))
1359 return false;
1360 } else if (Key == "use-external-names") {
1361 if (!parseScalarBool(I->getValue(), FS->UseExternalNames))
1362 return false;
1363 } else if (Key == "ignore-non-existent-contents") {
1364 if (!parseScalarBool(I->getValue(), FS->IgnoreNonExistentContents))
1365 return false;
1366 } else {
1367 llvm_unreachable("key missing from Keys")::llvm::llvm_unreachable_internal("key missing from Keys", "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 1367)
;
1368 }
1369 }
1370
1371 if (Stream.failed())
1372 return false;
1373
1374 if (!checkMissingKeys(Top, Keys))
1375 return false;
1376
1377 // Now that we sucessefully parsed the YAML file, canonicalize the internal
1378 // representation to a proper directory tree so that we can search faster
1379 // inside the VFS.
1380 for (std::unique_ptr<Entry> &E : RootEntries)
1381 uniqueOverlayTree(FS, E.get());
1382
1383 return true;
1384 }
1385};
1386} // end of anonymous namespace
1387
1388Entry::~Entry() = default;
1389
1390RedirectingFileSystem *
1391RedirectingFileSystem::create(std::unique_ptr<MemoryBuffer> Buffer,
1392 SourceMgr::DiagHandlerTy DiagHandler,
1393 StringRef YAMLFilePath, void *DiagContext,
1394 IntrusiveRefCntPtr<FileSystem> ExternalFS) {
1395
1396 SourceMgr SM;
1397 yaml::Stream Stream(Buffer->getMemBufferRef(), SM);
1398
1399 SM.setDiagHandler(DiagHandler, DiagContext);
1400 yaml::document_iterator DI = Stream.begin();
1401 yaml::Node *Root = DI->getRoot();
1402 if (DI == Stream.end() || !Root) {
1403 SM.PrintMessage(SMLoc(), SourceMgr::DK_Error, "expected root node");
1404 return nullptr;
1405 }
1406
1407 RedirectingFileSystemParser P(Stream);
1408
1409 std::unique_ptr<RedirectingFileSystem> FS(
1410 new RedirectingFileSystem(std::move(ExternalFS)));
1411
1412 if (!YAMLFilePath.empty()) {
1413 // Use the YAML path from -ivfsoverlay to compute the dir to be prefixed
1414 // to each 'external-contents' path.
1415 //
1416 // Example:
1417 // -ivfsoverlay dummy.cache/vfs/vfs.yaml
1418 // yields:
1419 // FS->ExternalContentsPrefixDir => /<absolute_path_to>/dummy.cache/vfs
1420 //
1421 SmallString<256> OverlayAbsDir = sys::path::parent_path(YAMLFilePath);
1422 std::error_code EC = llvm::sys::fs::make_absolute(OverlayAbsDir);
1423 assert(!EC && "Overlay dir final path must be absolute")((!EC && "Overlay dir final path must be absolute") ?
static_cast<void> (0) : __assert_fail ("!EC && \"Overlay dir final path must be absolute\""
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 1423, __PRETTY_FUNCTION__))
;
1424 (void)EC;
1425 FS->setExternalContentsPrefixDir(OverlayAbsDir);
1426 }
1427
1428 if (!P.parse(Root, FS.get()))
1429 return nullptr;
1430
1431 return FS.release();
1432}
1433
1434ErrorOr<Entry *> RedirectingFileSystem::lookupPath(const Twine &Path_) {
1435 SmallString<256> Path;
1436 Path_.toVector(Path);
1437
1438 // Handle relative paths
1439 if (std::error_code EC = makeAbsolute(Path))
1440 return EC;
1441
1442 // Canonicalize path by removing ".", "..", "./", etc components. This is
1443 // a VFS request, do bot bother about symlinks in the path components
1444 // but canonicalize in order to perform the correct entry search.
1445 if (UseCanonicalizedPaths) {
1446 Path = sys::path::remove_leading_dotslash(Path);
1447 sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
1448 }
1449
1450 if (Path.empty())
1451 return make_error_code(llvm::errc::invalid_argument);
1452
1453 sys::path::const_iterator Start = sys::path::begin(Path);
1454 sys::path::const_iterator End = sys::path::end(Path);
1455 for (const std::unique_ptr<Entry> &Root : Roots) {
1456 ErrorOr<Entry *> Result = lookupPath(Start, End, Root.get());
1457 if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
1458 return Result;
1459 }
1460 return make_error_code(llvm::errc::no_such_file_or_directory);
1461}
1462
1463ErrorOr<Entry *>
1464RedirectingFileSystem::lookupPath(sys::path::const_iterator Start,
1465 sys::path::const_iterator End, Entry *From) {
1466#ifndef LLVM_ON_WIN32
1467 assert(!isTraversalComponent(*Start) &&((!isTraversalComponent(*Start) && !isTraversalComponent
(From->getName()) && "Paths should not contain traversal components"
) ? static_cast<void> (0) : __assert_fail ("!isTraversalComponent(*Start) && !isTraversalComponent(From->getName()) && \"Paths should not contain traversal components\""
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 1469, __PRETTY_FUNCTION__))
1468 !isTraversalComponent(From->getName()) &&((!isTraversalComponent(*Start) && !isTraversalComponent
(From->getName()) && "Paths should not contain traversal components"
) ? static_cast<void> (0) : __assert_fail ("!isTraversalComponent(*Start) && !isTraversalComponent(From->getName()) && \"Paths should not contain traversal components\""
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 1469, __PRETTY_FUNCTION__))
1469 "Paths should not contain traversal components")((!isTraversalComponent(*Start) && !isTraversalComponent
(From->getName()) && "Paths should not contain traversal components"
) ? static_cast<void> (0) : __assert_fail ("!isTraversalComponent(*Start) && !isTraversalComponent(From->getName()) && \"Paths should not contain traversal components\""
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 1469, __PRETTY_FUNCTION__))
;
1470#else
1471 // FIXME: this is here to support windows, remove it once canonicalized
1472 // paths become globally default.
1473 if (Start->equals("."))
1474 ++Start;
1475#endif
1476
1477 StringRef FromName = From->getName();
1478
1479 // Forward the search to the next component in case this is an empty one.
1480 if (!FromName.empty()) {
1481 if (CaseSensitive ? !Start->equals(FromName)
1482 : !Start->equals_lower(FromName))
1483 // failure to match
1484 return make_error_code(llvm::errc::no_such_file_or_directory);
1485
1486 ++Start;
1487
1488 if (Start == End) {
1489 // Match!
1490 return From;
1491 }
1492 }
1493
1494 auto *DE = dyn_cast<RedirectingDirectoryEntry>(From);
1495 if (!DE)
1496 return make_error_code(llvm::errc::not_a_directory);
1497
1498 for (const std::unique_ptr<Entry> &DirEntry :
1499 llvm::make_range(DE->contents_begin(), DE->contents_end())) {
1500 ErrorOr<Entry *> Result = lookupPath(Start, End, DirEntry.get());
1501 if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
1502 return Result;
1503 }
1504 return make_error_code(llvm::errc::no_such_file_or_directory);
1505}
1506
1507static Status getRedirectedFileStatus(const Twine &Path, bool UseExternalNames,
1508 Status ExternalStatus) {
1509 Status S = ExternalStatus;
1510 if (!UseExternalNames)
1511 S = Status::copyWithNewName(S, Path.str());
1512 S.IsVFSMapped = true;
1513 return S;
1514}
1515
1516ErrorOr<Status> RedirectingFileSystem::status(const Twine &Path, Entry *E) {
1517 assert(E != nullptr)((E != nullptr) ? static_cast<void> (0) : __assert_fail
("E != nullptr", "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 1517, __PRETTY_FUNCTION__))
;
1518 if (auto *F = dyn_cast<RedirectingFileEntry>(E)) {
1519 ErrorOr<Status> S = ExternalFS->status(F->getExternalContentsPath());
1520 assert(!S || S->getName() == F->getExternalContentsPath())((!S || S->getName() == F->getExternalContentsPath()) ?
static_cast<void> (0) : __assert_fail ("!S || S->getName() == F->getExternalContentsPath()"
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 1520, __PRETTY_FUNCTION__))
;
1521 if (S)
1522 return getRedirectedFileStatus(Path, F->useExternalName(UseExternalNames),
1523 *S);
1524 return S;
1525 } else { // directory
1526 auto *DE = cast<RedirectingDirectoryEntry>(E);
1527 return Status::copyWithNewName(DE->getStatus(), Path.str());
1528 }
1529}
1530
1531ErrorOr<Status> RedirectingFileSystem::status(const Twine &Path) {
1532 ErrorOr<Entry *> Result = lookupPath(Path);
1533 if (!Result)
1534 return Result.getError();
1535 return status(Path, *Result);
1536}
1537
1538namespace {
1539/// Provide a file wrapper with an overriden status.
1540class FileWithFixedStatus : public File {
1541 std::unique_ptr<File> InnerFile;
1542 Status S;
1543
1544public:
1545 FileWithFixedStatus(std::unique_ptr<File> InnerFile, Status S)
1546 : InnerFile(std::move(InnerFile)), S(std::move(S)) {}
1547
1548 ErrorOr<Status> status() override { return S; }
1549 ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
1550 getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
1551 bool IsVolatile) override {
1552 return InnerFile->getBuffer(Name, FileSize, RequiresNullTerminator,
1553 IsVolatile);
1554 }
1555 std::error_code close() override { return InnerFile->close(); }
1556};
1557} // end anonymous namespace
1558
1559ErrorOr<std::unique_ptr<File>>
1560RedirectingFileSystem::openFileForRead(const Twine &Path) {
1561 ErrorOr<Entry *> E = lookupPath(Path);
1562 if (!E)
1563 return E.getError();
1564
1565 auto *F = dyn_cast<RedirectingFileEntry>(*E);
1566 if (!F) // FIXME: errc::not_a_file?
1567 return make_error_code(llvm::errc::invalid_argument);
1568
1569 auto Result = ExternalFS->openFileForRead(F->getExternalContentsPath());
1570 if (!Result)
1571 return Result;
1572
1573 auto ExternalStatus = (*Result)->status();
1574 if (!ExternalStatus)
1575 return ExternalStatus.getError();
1576
1577 // FIXME: Update the status with the name and VFSMapped.
1578 Status S = getRedirectedFileStatus(Path, F->useExternalName(UseExternalNames),
1579 *ExternalStatus);
1580 return std::unique_ptr<File>(
1581 llvm::make_unique<FileWithFixedStatus>(std::move(*Result), S));
1582}
1583
1584IntrusiveRefCntPtr<FileSystem>
1585vfs::getVFSFromYAML(std::unique_ptr<MemoryBuffer> Buffer,
1586 SourceMgr::DiagHandlerTy DiagHandler,
1587 StringRef YAMLFilePath,
1588 void *DiagContext,
1589 IntrusiveRefCntPtr<FileSystem> ExternalFS) {
1590 return RedirectingFileSystem::create(std::move(Buffer), DiagHandler,
1591 YAMLFilePath, DiagContext,
1592 std::move(ExternalFS));
1593}
1594
1595static void getVFSEntries(Entry *SrcE, SmallVectorImpl<StringRef> &Path,
1596 SmallVectorImpl<YAMLVFSEntry> &Entries) {
1597 auto Kind = SrcE->getKind();
1598 if (Kind == EK_Directory) {
1599 auto *DE = dyn_cast<RedirectingDirectoryEntry>(SrcE);
1600 assert(DE && "Must be a directory")((DE && "Must be a directory") ? static_cast<void>
(0) : __assert_fail ("DE && \"Must be a directory\""
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 1600, __PRETTY_FUNCTION__))
;
1601 for (std::unique_ptr<Entry> &SubEntry :
1602 llvm::make_range(DE->contents_begin(), DE->contents_end())) {
1603 Path.push_back(SubEntry->getName());
1604 getVFSEntries(SubEntry.get(), Path, Entries);
1605 Path.pop_back();
1606 }
1607 return;
1608 }
1609
1610 assert(Kind == EK_File && "Must be a EK_File")((Kind == EK_File && "Must be a EK_File") ? static_cast
<void> (0) : __assert_fail ("Kind == EK_File && \"Must be a EK_File\""
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 1610, __PRETTY_FUNCTION__))
;
1611 auto *FE = dyn_cast<RedirectingFileEntry>(SrcE);
1612 assert(FE && "Must be a file")((FE && "Must be a file") ? static_cast<void> (
0) : __assert_fail ("FE && \"Must be a file\"", "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 1612, __PRETTY_FUNCTION__))
;
1613 SmallString<128> VPath;
1614 for (auto &Comp : Path)
1615 llvm::sys::path::append(VPath, Comp);
1616 Entries.push_back(YAMLVFSEntry(VPath.c_str(), FE->getExternalContentsPath()));
1617}
1618
1619void vfs::collectVFSFromYAML(std::unique_ptr<MemoryBuffer> Buffer,
1620 SourceMgr::DiagHandlerTy DiagHandler,
1621 StringRef YAMLFilePath,
1622 SmallVectorImpl<YAMLVFSEntry> &CollectedEntries,
1623 void *DiagContext,
1624 IntrusiveRefCntPtr<FileSystem> ExternalFS) {
1625 RedirectingFileSystem *VFS = RedirectingFileSystem::create(
1626 std::move(Buffer), DiagHandler, YAMLFilePath, DiagContext,
1627 std::move(ExternalFS));
1628 ErrorOr<Entry *> RootE = VFS->lookupPath("/");
1629 if (!RootE)
1630 return;
1631 SmallVector<StringRef, 8> Components;
1632 Components.push_back("/");
1633 getVFSEntries(*RootE, Components, CollectedEntries);
1634}
1635
1636UniqueID vfs::getNextVirtualUniqueID() {
1637 static std::atomic<unsigned> UID;
1638 unsigned ID = ++UID;
1639 // The following assumes that uint64_t max will never collide with a real
1640 // dev_t value from the OS.
1641 return UniqueID(std::numeric_limits<uint64_t>::max(), ID);
1642}
1643
1644void YAMLVFSWriter::addFileMapping(StringRef VirtualPath, StringRef RealPath) {
1645 assert(sys::path::is_absolute(VirtualPath) && "virtual path not absolute")((sys::path::is_absolute(VirtualPath) && "virtual path not absolute"
) ? static_cast<void> (0) : __assert_fail ("sys::path::is_absolute(VirtualPath) && \"virtual path not absolute\""
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 1645, __PRETTY_FUNCTION__))
;
1646 assert(sys::path::is_absolute(RealPath) && "real path not absolute")((sys::path::is_absolute(RealPath) && "real path not absolute"
) ? static_cast<void> (0) : __assert_fail ("sys::path::is_absolute(RealPath) && \"real path not absolute\""
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 1646, __PRETTY_FUNCTION__))
;
1647 assert(!pathHasTraversal(VirtualPath) && "path traversal is not supported")((!pathHasTraversal(VirtualPath) && "path traversal is not supported"
) ? static_cast<void> (0) : __assert_fail ("!pathHasTraversal(VirtualPath) && \"path traversal is not supported\""
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 1647, __PRETTY_FUNCTION__))
;
1648 Mappings.emplace_back(VirtualPath, RealPath);
1649}
1650
1651namespace {
1652class JSONWriter {
1653 llvm::raw_ostream &OS;
1654 SmallVector<StringRef, 16> DirStack;
1655 inline unsigned getDirIndent() { return 4 * DirStack.size(); }
1656 inline unsigned getFileIndent() { return 4 * (DirStack.size() + 1); }
1657 bool containedIn(StringRef Parent, StringRef Path);
1658 StringRef containedPart(StringRef Parent, StringRef Path);
1659 void startDirectory(StringRef Path);
1660 void endDirectory();
1661 void writeEntry(StringRef VPath, StringRef RPath);
1662
1663public:
1664 JSONWriter(llvm::raw_ostream &OS) : OS(OS) {}
1665 void write(ArrayRef<YAMLVFSEntry> Entries, Optional<bool> UseExternalNames,
1666 Optional<bool> IsCaseSensitive, Optional<bool> IsOverlayRelative,
1667 Optional<bool> IgnoreNonExistentContents, StringRef OverlayDir);
1668};
1669}
1670
1671bool JSONWriter::containedIn(StringRef Parent, StringRef Path) {
1672 using namespace llvm::sys;
1673 // Compare each path component.
1674 auto IParent = path::begin(Parent), EParent = path::end(Parent);
1675 for (auto IChild = path::begin(Path), EChild = path::end(Path);
1676 IParent != EParent && IChild != EChild; ++IParent, ++IChild) {
1677 if (*IParent != *IChild)
1678 return false;
1679 }
1680 // Have we exhausted the parent path?
1681 return IParent == EParent;
1682}
1683
1684StringRef JSONWriter::containedPart(StringRef Parent, StringRef Path) {
1685 assert(!Parent.empty())((!Parent.empty()) ? static_cast<void> (0) : __assert_fail
("!Parent.empty()", "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 1685, __PRETTY_FUNCTION__))
;
1686 assert(containedIn(Parent, Path))((containedIn(Parent, Path)) ? static_cast<void> (0) : __assert_fail
("containedIn(Parent, Path)", "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 1686, __PRETTY_FUNCTION__))
;
1687 return Path.slice(Parent.size() + 1, StringRef::npos);
1688}
1689
1690void JSONWriter::startDirectory(StringRef Path) {
1691 StringRef Name =
1692 DirStack.empty() ? Path : containedPart(DirStack.back(), Path);
1693 DirStack.push_back(Path);
1694 unsigned Indent = getDirIndent();
1695 OS.indent(Indent) << "{\n";
1696 OS.indent(Indent + 2) << "'type': 'directory',\n";
1697 OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(Name) << "\",\n";
1698 OS.indent(Indent + 2) << "'contents': [\n";
1699}
1700
1701void JSONWriter::endDirectory() {
1702 unsigned Indent = getDirIndent();
1703 OS.indent(Indent + 2) << "]\n";
1704 OS.indent(Indent) << "}";
1705
1706 DirStack.pop_back();
1707}
1708
1709void JSONWriter::writeEntry(StringRef VPath, StringRef RPath) {
1710 unsigned Indent = getFileIndent();
1711 OS.indent(Indent) << "{\n";
1712 OS.indent(Indent + 2) << "'type': 'file',\n";
1713 OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(VPath) << "\",\n";
1714 OS.indent(Indent + 2) << "'external-contents': \""
1715 << llvm::yaml::escape(RPath) << "\"\n";
1716 OS.indent(Indent) << "}";
1717}
1718
1719void JSONWriter::write(ArrayRef<YAMLVFSEntry> Entries,
1720 Optional<bool> UseExternalNames,
1721 Optional<bool> IsCaseSensitive,
1722 Optional<bool> IsOverlayRelative,
1723 Optional<bool> IgnoreNonExistentContents,
1724 StringRef OverlayDir) {
1725 using namespace llvm::sys;
1726
1727 OS << "{\n"
1728 " 'version': 0,\n";
1729 if (IsCaseSensitive.hasValue())
1730 OS << " 'case-sensitive': '"
1731 << (IsCaseSensitive.getValue() ? "true" : "false") << "',\n";
1732 if (UseExternalNames.hasValue())
1733 OS << " 'use-external-names': '"
1734 << (UseExternalNames.getValue() ? "true" : "false") << "',\n";
1735 bool UseOverlayRelative = false;
1736 if (IsOverlayRelative.hasValue()) {
1737 UseOverlayRelative = IsOverlayRelative.getValue();
1738 OS << " 'overlay-relative': '"
1739 << (UseOverlayRelative ? "true" : "false") << "',\n";
1740 }
1741 if (IgnoreNonExistentContents.hasValue())
1742 OS << " 'ignore-non-existent-contents': '"
1743 << (IgnoreNonExistentContents.getValue() ? "true" : "false") << "',\n";
1744 OS << " 'roots': [\n";
1745
1746 if (!Entries.empty()) {
1747 const YAMLVFSEntry &Entry = Entries.front();
1748 startDirectory(path::parent_path(Entry.VPath));
1749
1750 StringRef RPath = Entry.RPath;
1751 if (UseOverlayRelative) {
1752 unsigned OverlayDirLen = OverlayDir.size();
1753 assert(RPath.substr(0, OverlayDirLen) == OverlayDir &&((RPath.substr(0, OverlayDirLen) == OverlayDir && "Overlay dir must be contained in RPath"
) ? static_cast<void> (0) : __assert_fail ("RPath.substr(0, OverlayDirLen) == OverlayDir && \"Overlay dir must be contained in RPath\""
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 1754, __PRETTY_FUNCTION__))
1754 "Overlay dir must be contained in RPath")((RPath.substr(0, OverlayDirLen) == OverlayDir && "Overlay dir must be contained in RPath"
) ? static_cast<void> (0) : __assert_fail ("RPath.substr(0, OverlayDirLen) == OverlayDir && \"Overlay dir must be contained in RPath\""
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 1754, __PRETTY_FUNCTION__))
;
1755 RPath = RPath.slice(OverlayDirLen, RPath.size());
1756 }
1757
1758 writeEntry(path::filename(Entry.VPath), RPath);
1759
1760 for (const auto &Entry : Entries.slice(1)) {
1761 StringRef Dir = path::parent_path(Entry.VPath);
1762 if (Dir == DirStack.back())
1763 OS << ",\n";
1764 else {
1765 while (!DirStack.empty() && !containedIn(DirStack.back(), Dir)) {
1766 OS << "\n";
1767 endDirectory();
1768 }
1769 OS << ",\n";
1770 startDirectory(Dir);
1771 }
1772 StringRef RPath = Entry.RPath;
1773 if (UseOverlayRelative) {
1774 unsigned OverlayDirLen = OverlayDir.size();
1775 assert(RPath.substr(0, OverlayDirLen) == OverlayDir &&((RPath.substr(0, OverlayDirLen) == OverlayDir && "Overlay dir must be contained in RPath"
) ? static_cast<void> (0) : __assert_fail ("RPath.substr(0, OverlayDirLen) == OverlayDir && \"Overlay dir must be contained in RPath\""
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 1776, __PRETTY_FUNCTION__))
1776 "Overlay dir must be contained in RPath")((RPath.substr(0, OverlayDirLen) == OverlayDir && "Overlay dir must be contained in RPath"
) ? static_cast<void> (0) : __assert_fail ("RPath.substr(0, OverlayDirLen) == OverlayDir && \"Overlay dir must be contained in RPath\""
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 1776, __PRETTY_FUNCTION__))
;
1777 RPath = RPath.slice(OverlayDirLen, RPath.size());
1778 }
1779 writeEntry(path::filename(Entry.VPath), RPath);
1780 }
1781
1782 while (!DirStack.empty()) {
1783 OS << "\n";
1784 endDirectory();
1785 }
1786 OS << "\n";
1787 }
1788
1789 OS << " ]\n"
1790 << "}\n";
1791}
1792
1793void YAMLVFSWriter::write(llvm::raw_ostream &OS) {
1794 std::sort(Mappings.begin(), Mappings.end(),
1795 [](const YAMLVFSEntry &LHS, const YAMLVFSEntry &RHS) {
1796 return LHS.VPath < RHS.VPath;
1797 });
1798
1799 JSONWriter(OS).write(Mappings, UseExternalNames, IsCaseSensitive,
1800 IsOverlayRelative, IgnoreNonExistentContents,
1801 OverlayDir);
1802}
1803
1804VFSFromYamlDirIterImpl::VFSFromYamlDirIterImpl(
1805 const Twine &_Path, RedirectingFileSystem &FS,
1806 RedirectingDirectoryEntry::iterator Begin,
1807 RedirectingDirectoryEntry::iterator End, std::error_code &EC)
1808 : Dir(_Path.str()), FS(FS), Current(Begin), End(End) {
1809 while (Current != End) {
1810 SmallString<128> PathStr(Dir);
1811 llvm::sys::path::append(PathStr, (*Current)->getName());
1812 llvm::ErrorOr<vfs::Status> S = FS.status(PathStr);
1813 if (S) {
1814 CurrentEntry = *S;
1815 return;
1816 }
1817 // Skip entries which do not map to a reliable external content.
1818 if (FS.ignoreNonExistentContents() &&
1819 S.getError() == llvm::errc::no_such_file_or_directory) {
1820 ++Current;
1821 continue;
1822 } else {
1823 EC = S.getError();
1824 break;
1825 }
1826 }
1827}
1828
1829std::error_code VFSFromYamlDirIterImpl::increment() {
1830 assert(Current != End && "cannot iterate past end")((Current != End && "cannot iterate past end") ? static_cast
<void> (0) : __assert_fail ("Current != End && \"cannot iterate past end\""
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 1830, __PRETTY_FUNCTION__))
;
1831 while (++Current != End) {
1832 SmallString<128> PathStr(Dir);
1833 llvm::sys::path::append(PathStr, (*Current)->getName());
1834 llvm::ErrorOr<vfs::Status> S = FS.status(PathStr);
1835 if (!S) {
1836 // Skip entries which do not map to a reliable external content.
1837 if (FS.ignoreNonExistentContents() &&
1838 S.getError() == llvm::errc::no_such_file_or_directory) {
1839 continue;
1840 } else {
1841 return S.getError();
1842 }
1843 }
1844 CurrentEntry = *S;
1845 break;
1846 }
1847
1848 if (Current == End)
1849 CurrentEntry = Status();
1850 return std::error_code();
1851}
1852
1853vfs::recursive_directory_iterator::recursive_directory_iterator(FileSystem &FS_,
1854 const Twine &Path,
1855 std::error_code &EC)
1856 : FS(&FS_) {
1857 directory_iterator I = FS->dir_begin(Path, EC);
1858 if (I != directory_iterator()) {
1859 State = std::make_shared<IterState>();
1860 State->push(I);
1861 }
1862}
1863
1864vfs::recursive_directory_iterator &
1865recursive_directory_iterator::increment(std::error_code &EC) {
1866 assert(FS && State && !State->empty() && "incrementing past end")((FS && State && !State->empty() &&
"incrementing past end") ? static_cast<void> (0) : __assert_fail
("FS && State && !State->empty() && \"incrementing past end\""
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 1866, __PRETTY_FUNCTION__))
;
1867 assert(State->top()->isStatusKnown() && "non-canonical end iterator")((State->top()->isStatusKnown() && "non-canonical end iterator"
) ? static_cast<void> (0) : __assert_fail ("State->top()->isStatusKnown() && \"non-canonical end iterator\""
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Basic/VirtualFileSystem.cpp"
, 1867, __PRETTY_FUNCTION__))
;
1868 vfs::directory_iterator End;
1869 if (State->top()->isDirectory()) {
1870 vfs::directory_iterator I = FS->dir_begin(State->top()->getName(), EC);
1871 if (I != End) {
1872 State->push(I);
1873 return *this;
1874 }
1875 }
1876
1877 while (!State->empty() && State->top().increment(EC) == End)
1878 State->pop();
1879
1880 if (State->empty())
1881 State.reset(); // end iterator
1882
1883 return *this;
1884}