LLVM: lib/Support/VirtualFileSystem.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

24#include "llvm/Config/llvm-config.h"

40#include

41#include

42#include

43#include

44#include

45#include

46#include

47#include

48#include

49#include <system_error>

50#include

51#include

52

53using namespace llvm;

55

62

67

70 perms Perms)

71 : Name(Name.str()), UID(UID), MTime(MTime), User(User), Group(Group),

73

75 return Status(In.getName(), In.getUniqueID(), In.getLastModificationTime(),

76 In.getUser(), In.getGroup(), NewSize, In.getType(),

77 In.getPermissions());

78}

79

81 return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),

82 In.getUser(), In.getGroup(), In.getSize(), In.getType(),

83 In.getPermissions());

84}

85

87 return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),

88 In.getUser(), In.getGroup(), In.getSize(), In.type(),

89 In.permissions());

90}

91

95}

96

98

100

103}

104

106

108

111}

112

114

116

119 bool RequiresNullTerminator, bool IsVolatile,

120 bool IsText) {

122 if (F)

123 return F.getError();

124

125 return (*F)->getBuffer(Name, FileSize, RequiresNullTerminator, IsVolatile);

126}

127

130 return {};

131

133 if (!WorkingDir)

134 return WorkingDir.getError();

135

137 return {};

138}

139

143}

144

147}

148

152}

153

155 auto StatusA = status(A);

156 if (!StatusA)

157 return StatusA.getError();

158 auto StatusB = status(B);

159 if (!StatusB)

160 return StatusB.getError();

161 return StatusA->equivalent(*StatusB);

162}

163

164#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)

166#endif

167

168#ifndef NDEBUG

170 return Component == ".." || Component == ".";

171}

172

175

178 return true;

179 return false;

180}

181#endif

182

183

184

185

186

187namespace {

188

189

190class RealFile : public File {

191 friend class RealFileSystem;

192

195 std::string RealName;

196

198 : FD(RawFD), S(NewName, {}, {}, {}, {}, {},

200 RealName(NewRealPathName.str()) {

201 assert(FD != kInvalidFile && "Invalid or inactive file descriptor");

202 }

203

204public:

205 ~RealFile() override;

206

210 int64_t FileSize,

211 bool RequiresNullTerminator,

212 bool IsVolatile) override;

213 std::error_code close() override;

214 void setPath(const Twine &Path) override;

215};

216

217}

218

219RealFile::~RealFile() { close(); }

220

222 assert(FD != kInvalidFile && "cannot stat closed file");

223 if (!S.isStatusKnown()) {

225 if (std::error_code EC = sys::fs::status(FD, RealStatus))

226 return EC;

228 }

229 return S;

230}

231

233 return RealName.empty() ? S.getName().str() : RealName;

234}

235

237RealFile::getBuffer(const Twine &Name, int64_t FileSize,

238 bool RequiresNullTerminator, bool IsVolatile) {

239 assert(FD != kInvalidFile && "cannot get buffer for closed file");

241 IsVolatile);

242}

243

244std::error_code RealFile::close() {

247 return EC;

248}

249

250void RealFile::setPath(const Twine &Path) {

251 RealName = Path.str();

254}

255

256namespace {

257

258

259

260

261

262

263

264

265

266class RealFileSystem : public FileSystem {

267public:

268 explicit RealFileSystem(bool LinkCWDToProcess) {

269 if (!LinkCWDToProcess) {

272 WD = EC;

274 WD = WorkingDirectory{PWD, PWD};

275 else

276 WD = WorkingDirectory{PWD, RealPWD};

277 }

278 }

279

283 openFileForReadBinary(const Twine &Path) override;

285

287 std::error_code setCurrentWorkingDirectory(const Twine &Path) override;

288 std::error_code isLocal(const Twine &Path, bool &Result) override;

289 std::error_code getRealPath(const Twine &Path,

291

292protected:

294 unsigned IndentLevel) const override;

295

296private:

297

298

300 if (!WD || !*WD)

302 Path.toVector(Storage);

304 return Storage;

305 }

306

311 adjustPath(Name, Storage), Flags, &RealName);

312 if (!FDOrErr)

314 return std::unique_ptr(

315 new RealFile(*FDOrErr, Name.str(), RealName.str()));

316 }

317

318 struct WorkingDirectory {

319

321

323 };

324 std::optional<llvm::ErrorOr> WD;

325};

326

327}

328

332 if (std::error_code EC =

334 return EC;

336}

337

339RealFileSystem::openFileForRead(const Twine &Name) {

341}

342

344RealFileSystem::openFileForReadBinary(const Twine &Name) {

346}

347

349 if (WD && *WD)

350 return std::string(WD->get().Specified);

351 if (WD)

352 return WD->getError();

353

356 return EC;

357 return std::string(Dir);

358}

359

360std::error_code RealFileSystem::setCurrentWorkingDirectory(const Twine &Path) {

361 if (!WD)

363

365 adjustPath(Path, Storage).toVector(Absolute);

366 bool IsDir;

368 return Err;

369 if (!IsDir)

370 return std::make_error_code(std::errc::not_a_directory);

372 return Err;

374 return std::error_code();

375}

376

377std::error_code RealFileSystem::isLocal(const Twine &Path, bool &Result) {

380}

381

382std::error_code RealFileSystem::getRealPath(const Twine &Path,

386}

387

389 unsigned IndentLevel) const {

390 printIndent(OS, IndentLevel);

391 OS << "RealFileSystem using ";

392 if (WD)

393 OS << "own";

394 else

395 OS << "process";

396 OS << " CWD\n";

397}

398

401 return FS;

402}

403

405 return std::make_unique(false);

406}

407

408namespace {

409

412

413public:

414 RealFSDirIter(const Twine &Path, std::error_code &EC) : Iter(Path, EC) {

417 }

418

419 std::error_code increment() override {

420 std::error_code EC;

425 return EC;

426 }

427};

428

429}

430

432 std::error_code &EC) {

435 std::make_shared(adjustPath(Dir, Storage), EC));

436}

437

438

439

440

441

443 FSList.push_back(std::move(BaseFS));

444}

445

448

449

451}

452

454

459 }

461}

462

464

466 if ((*I)->exists(Path))

467 return true;

468 }

469 return false;

470}

471

474

476 auto Result = (*I)->openFileForRead(Path);

478 return Result;

479 }

481}

482

485

486 return FSList.front()->getCurrentWorkingDirectory();

487}

488

489std::error_code

491 for (auto &FS : FSList)

492 if (std::error_code EC = FS->setCurrentWorkingDirectory(Path))

493 return EC;

494 return {};

495}

496

498 for (auto &FS : FSList)

499 if (FS->exists(Path))

500 return FS->isLocal(Path, Result);

502}

503

506 for (const auto &FS : FSList)

507 if (FS->exists(Path))

508 return FS->getRealPath(Path, Output);

510}

511

514 Callback(*FS);

515 FS->visitChildFileSystems(Callback);

516 }

517}

518

520 unsigned IndentLevel) const {

521 printIndent(OS, IndentLevel);

522 OS << "OverlayFileSystem\n";

523 if (Type == PrintType::Summary)

524 return;

525

526 if (Type == PrintType::Contents)

527 Type = PrintType::Summary;

529 FS->print(OS, Type, IndentLevel + 1);

530}

531

533

534namespace {

535

536

539

540

542

544

546

547

548

549 std::error_code incrementIter(bool IsFirstTime) {

550 while (!IterList.empty()) {

551 CurrentDirIter = IterList.back();

554 break;

555 }

556

558 return errc::no_such_file_or_directory;

559 return {};

560 }

561

562 std::error_code incrementDirIter(bool IsFirstTime) {

564 "incrementing past end");

565 std::error_code EC;

566 if (!IsFirstTime)

569 EC = incrementIter(IsFirstTime);

570 return EC;

571 }

572

573 std::error_code incrementImpl(bool IsFirstTime) {

574 while (true) {

575 std::error_code EC = incrementDirIter(IsFirstTime);

578 return EC;

579 }

580 CurrentEntry = *CurrentDirIter;

583 return EC;

584 }

586 }

587

588public:

590 std::error_code &EC) {

591 for (const auto &FS : FileSystems) {

592 std::error_code FEC;

594 if (FEC && FEC != errc::no_such_file_or_directory) {

595 EC = FEC;

596 return;

597 }

598 if (!FEC)

600 }

601 EC = incrementImpl(true);

602 }

603

605 std::error_code &EC)

606 : IterList(DirIters) {

607 EC = incrementImpl(true);

608 }

609

610 std::error_code increment() override { return incrementImpl(false); }

611};

612

613}

614

616 std::error_code &EC) {

618 std::make_shared(FSList, Dir.str(), EC));

619 if (EC)

620 return {};

621 return Combined;

622}

623

624void ProxyFileSystem::anchor() {}

625

626namespace llvm {

627namespace vfs {

628

630

636};

637

638

639

642 std::string FileName;

643

644public:

646 : Kind(Kind), FileName(std::string(llvm::sys::path::filename(FileName))) {

647 }

649

650

651

652

654

655

658 virtual std::string toString(unsigned Indent) const = 0;

659};

660

663 std::unique_ptrllvm::MemoryBuffer Buffer;

664

665public:

668 Buffer(std::move(Buffer)) {}

669

671 return Status::copyWithNewName(Stat, RequestedName);

672 }

674

675 std::string toString(unsigned Indent) const override {

676 return (std::string(Indent, ' ') + Stat.getName() + "\n").str();

677 }

678

681 }

682};

683

684namespace {

685

686class InMemoryHardLink : public InMemoryNode {

687 const InMemoryFile &ResolvedFile;

688

689public:

690 InMemoryHardLink(StringRef Path, const InMemoryFile &ResolvedFile)

691 : InMemoryNode(Path, IME_HardLink), ResolvedFile(ResolvedFile) {}

692 const InMemoryFile &getResolvedFile() const { return ResolvedFile; }

693

694 Status getStatus(const Twine &RequestedName) const override {

695 return ResolvedFile.getStatus(RequestedName);

696 }

697

698 std::string toString(unsigned Indent) const override {

699 return std::string(Indent, ' ') + "HardLink to -> " +

700 ResolvedFile.toString(0);

701 }

702

703 static bool classof(const InMemoryNode *N) {

705 }

706};

707

708class InMemorySymbolicLink : public InMemoryNode {

709 std::string TargetPath;

711

712public:

715 Stat(Stat) {}

716

717 std::string toString(unsigned Indent) const override {

718 return std::string(Indent, ' ') + "SymbolicLink to -> " + TargetPath;

719 }

720

721 Status getStatus(const Twine &RequestedName) const override {

722 return Status::copyWithNewName(Stat, RequestedName);

723 }

724

725 StringRef getTargetPath() const { return TargetPath; }

726

727 static bool classof(const InMemoryNode *N) {

729 }

730};

731

732

733

734

735class InMemoryFileAdaptor : public File {

736 const InMemoryFile &Node;

737

738 std::string RequestedName;

739

740public:

741 explicit InMemoryFileAdaptor(const InMemoryFile &Node,

742 std::string RequestedName)

744

746 return Node.getStatus(RequestedName);

747 }

748

750 getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,

751 bool IsVolatile) override {

755 }

756

757 std::error_code close() override { return {}; }

758

759 void setPath(const Twine &Path) override { RequestedName = Path.str(); }

760};

761}

762

765 std::map<std::string, std::unique_ptr, std::less<>> Entries;

766

767public:

770

771

772

773

775 return Status::copyWithNewName(Stat, RequestedName);

776 }

777

779

781 auto I = Entries.find(Name);

782 if (I != Entries.end())

783 return I->second.get();

784 return nullptr;

785 }

786

788 return Entries.emplace(Name, std::move(Child)).first->second.get();

789 }

790

792

795

796 std::string toString(unsigned Indent) const override {

797 std::string Result =

798 (std::string(Indent, ' ') + Stat.getName() + "\n").str();

799 for (const auto &Entry : Entries)

800 Result += Entry.second->toString(Indent + 2);

801 return Result;

802 }

803

806 }

807};

808

809}

810

811

812

813

817}

822}

826}

827

830 (Type == sys::fs::file_type::directory_file)

832 : getFileID(DirUID, Name, Buffer ? Buffer->getBuffer() : "");

833

835 Group, Buffer ? Buffer->getBufferSize() : 0, Type, Perms);

836}

837

839 : Root(new detail::InMemoryDirectory(

842 llvm::sys::fs::file_type::directory_file,

843 llvm::sys::fs::perms::all_all))),

844 UseNormalizedPaths(UseNormalizedPaths) {}

845

847

849 return Root->toString(0);

850}

851

852bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime,

853 std::unique_ptrllvm::MemoryBuffer Buffer,

854 std::optional<uint32_t> User,

855 std::optional<uint32_t> Group,

856 std::optionalllvm::sys::fs::file\_type Type,

857 std::optionalllvm::sys::fs::perms Perms,

858 MakeNodeFn MakeNode) {

860 P.toVector(Path);

861

862

865 (void)EC;

866

869

870 if (Path.empty())

871 return false;

872

875 const auto ResolvedUser = User.value_or(0);

876 const auto ResolvedGroup = Group.value_or(0);

879

880

882

884 while (true) {

886 ++I;

887 if (I == E)

888 break;

890 if (!Node) {

891

893 StringRef(Path.str().begin(), Name.end() - Path.str().begin()),

897 Dir = castdetail::InMemoryDirectory(Dir->addChild(

898 Name, std::make_uniquedetail::InMemoryDirectory(std::move(Stat))));

899 continue;

900 }

901

902 if (!isadetail::InMemoryDirectory(Node))

903 return false;

904 Dir = castdetail::InMemoryDirectory(Node);

905 }

909 MakeNode({Dir->getUniqueID(), Path, Name, ModificationTime,

910 std::move(Buffer), ResolvedUser, ResolvedGroup,

911 ResolvedType, ResolvedPerms}));

912 return true;

913 }

914 if (isadetail::InMemoryDirectory(Node))

916

917 assert((isadetail::InMemoryFile(Node) ||

918 isadetail::InMemoryHardLink(Node)) &&

919 "Must be either file, hardlink or directory!");

920

921

922 if (auto *Link = dyn_castdetail::InMemoryHardLink(Node)) {

923 return Link->getResolvedFile().getBuffer()->getBuffer() ==

924 Buffer->getBuffer();

925 }

926 return castdetail::InMemoryFile(Node)->getBuffer()->getBuffer() ==

927 Buffer->getBuffer();

928}

929

930bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime,

931 std::unique_ptrllvm::MemoryBuffer Buffer,

932 std::optional<uint32_t> User,

933 std::optional<uint32_t> Group,

934 std::optionalllvm::sys::fs::file\_type Type,

935 std::optionalllvm::sys::fs::perms Perms) {

936 return addFile(P, ModificationTime, std::move(Buffer), User, Group, Type,

937 Perms,

939 -> std::unique_ptrdetail::InMemoryNode {

942 return std::make_uniquedetail::InMemoryDirectory(Stat);

943 return std::make_uniquedetail::InMemoryFile(

944 Stat, std::move(NNI.Buffer));

945 });

946}

947

949 const Twine &P, time_t ModificationTime,

951 std::optional<uint32_t> Group, std::optionalllvm::sys::fs::file\_type Type,

952 std::optionalllvm::sys::fs::perms Perms) {

954 std::move(User), std::move(Group), std::move(Type),

955 std::move(Perms),

957 -> std::unique_ptrdetail::InMemoryNode {

960 return std::make_uniquedetail::InMemoryDirectory(Stat);

961 return std::make_uniquedetail::InMemoryFile(

962 Stat, std::move(NNI.Buffer));

963 });

964}

965

967InMemoryFileSystem::lookupNode(const Twine &P, bool FollowFinalSymlink,

968 size_t SymlinkDepth) const {

970 P.toVector(Path);

971

972

975 (void)EC;

976

979

981 if (Path.empty())

983

985 while (true) {

987 ++I;

988 if (!Node)

990

991 if (auto Symlink = dyn_castdetail::InMemorySymbolicLink(Node)) {

992

993

994 if (I == E && !FollowFinalSymlink)

996

999

1001 if (std::error_code EC = makeAbsolute(TargetPath))

1002 return EC;

1003

1004

1005

1006

1007

1009 lookupNode(TargetPath, true, SymlinkDepth + 1);

1012

1013 if (!isadetail::InMemoryDirectory(*Target))

1015

1016

1017 Dir = castdetail::InMemoryDirectory(*Target);

1018 continue;

1019 }

1020

1021

1022 if (auto File = dyn_castdetail::InMemoryFile(Node)) {

1023 if (I == E)

1026 }

1027

1028

1029 if (auto File = dyn_castdetail::InMemoryHardLink(Node)) {

1030 if (I == E)

1033 }

1034

1035 Dir = castdetail::InMemoryDirectory(Node);

1036 if (I == E)

1038 }

1039}

1040

1043 auto NewLinkNode = lookupNode(NewLink, false);

1044

1045

1046

1047 auto TargetNode = lookupNode(Target, true);

1048

1049

1050 if (!TargetNode || NewLinkNode || !isadetail::InMemoryFile(*TargetNode))

1051 return false;

1052 return addFile(NewLink, 0, nullptr, std::nullopt, std::nullopt, std::nullopt,

1054 return std::make_uniquedetail::InMemoryHardLink(

1056 *castdetail::InMemoryFile(*TargetNode));

1057 });

1058}

1059

1061 const Twine &NewLink, const Twine &Target, time_t ModificationTime,

1062 std::optional<uint32_t> User, std::optional<uint32_t> Group,

1063 std::optionalllvm::sys::fs::perms Perms) {

1064 auto NewLinkNode = lookupNode(NewLink, false);

1065 if (NewLinkNode)

1066 return false;

1067

1069 NewLink.toVector(NewLinkStr);

1070 Target.toVector(TargetStr);

1071

1072 return addFile(NewLinkStr, ModificationTime, nullptr, User, Group,

1075 return std::make_uniquedetail::InMemorySymbolicLink(

1076 NewLinkStr, TargetStr, NNI.makeStatus());

1077 });

1078}

1079

1081 auto Node = lookupNode(Path, true);

1082 if (Node)

1083 return (*Node)->getStatus(Path);

1084 return Node.getError();

1085}

1086

1089 auto Node = lookupNode(Path,true);

1090 if (!Node)

1091 return Node.getError();

1092

1093

1094

1095 if (auto *F = dyn_castdetail::InMemoryFile(*Node))

1096 return std::unique_ptr(

1097 new detail::InMemoryFileAdaptor(*F, Path.str()));

1098

1099

1101}

1102

1103

1108 std::string RequestedDirName;

1109

1110 void setCurrentEntry() {

1111 if (I != E) {

1115 switch (I->second->getKind()) {

1119 break;

1122 break;

1124 if (auto SymlinkTarget =

1125 FS->lookupNode(Path, true)) {

1126 Path = SymlinkTarget.getName();

1127 Type = (*SymlinkTarget)->getStatus(Path).getType();

1128 }

1129 break;

1130 }

1132 } else {

1133

1134

1136 }

1137 }

1138

1139public:

1141

1144 std::string RequestedDirName)

1145 : FS(FS), I(Dir.begin()), E(Dir.end()),

1146 RequestedDirName(std::move(RequestedDirName)) {

1147 setCurrentEntry();

1148 }

1149

1151 ++I;

1152 setCurrentEntry();

1153 return {};

1154 }

1155};

1156

1158 std::error_code &EC) {

1159 auto Node = lookupNode(Dir, true);

1160 if (!Node) {

1161 EC = Node.getError();

1163 }

1164

1165 if (auto *DirNode = dyn_castdetail::InMemoryDirectory(*Node))

1167 std::make_shared(this, *DirNode, Dir.str()));

1168

1171}

1172

1175 P.toVector(Path);

1176

1177

1180 (void)EC;

1181

1184

1185 if (!Path.empty())

1186 WorkingDirectory = std::string(Path);

1187 return {};

1188}

1189

1193 if (!CWD || CWD->empty())

1195 Path.toVector(Output);

1197 return EC;

1199 return {};

1200}

1201

1203 Result = false;

1204 return {};

1205}

1206

1208 unsigned IndentLevel) const {

1209 printIndent(OS, IndentLevel);

1210 OS << "InMemoryFileSystem\n";

1211}

1212

1213}

1214}

1215

1216

1217

1218

1219

1220namespace {

1221

1223

1225 const size_t n = Path.find_first_of("/\\");

1226

1227 if (n != static_cast<size_t>(-1))

1230 return style;

1231}

1232

1233

1235

1237

1238

1239

1243 return result;

1244}

1245

1246

1247static bool isFileNotFound(std::error_code EC,

1249 if (E && !isaRedirectingFileSystem::DirectoryRemapEntry(E))

1250 return false;

1252}

1253

1254}

1255

1256

1259 if (ExternalFS)

1260 if (auto ExternalWorkingDirectory =

1261 ExternalFS->getCurrentWorkingDirectory()) {

1262 WorkingDirectory = *ExternalWorkingDirectory;

1263 }

1264}

1265

1266

1267

1270 std::string Dir;

1272

1273 std::error_code incrementImpl(bool IsFirstTime) {

1274 assert((IsFirstTime || Current != End) && "cannot iterate past end");

1275 if (!IsFirstTime)

1276 ++Current;

1277 if (Current != End) {

1281 switch ((*Current)->getKind()) {

1283 [[fallthrough]];

1286 break;

1289 break;

1290 }

1292 } else {

1294 }

1295 return {};

1296 };

1297

1298public:

1302 : Dir(Path.str()), Current(Begin), End(End) {

1303 EC = incrementImpl(true);

1304 }

1305

1307 return incrementImpl(false);

1308 }

1309};

1310

1311namespace {

1312

1313

1314

1316 std::string Dir;

1319

1320public:

1321 RedirectingFSDirRemapIterImpl(std::string DirPath,

1323 : Dir(std::move(DirPath)), DirStyle(getExistingStyle(Dir)),

1324 ExternalIter(ExtIter) {

1326 setCurrentEntry();

1327 }

1328

1329 void setCurrentEntry() {

1333

1336

1337 CurrentEntry = directory_entry(std::string(NewPath), ExternalIter->type());

1338 }

1339

1340 std::error_code increment() override {

1341 std::error_code EC;

1344 setCurrentEntry();

1345 else

1347 return EC;

1348 }

1349};

1350}

1351

1354 return WorkingDirectory;

1355}

1356

1357std::error_code

1359

1362

1364 Path.toVector(AbsolutePath);

1365 if (std::error_code EC = makeAbsolute(AbsolutePath))

1366 return EC;

1367 WorkingDirectory = std::string(AbsolutePath);

1368 return {};

1369}

1370

1372 bool &Result) {

1375

1376 if (makeAbsolute(Path))

1377 return {};

1378

1379 return ExternalFS->isLocal(Path, Result);

1380}

1381

1383

1387

1388

1389

1390 return {};

1391

1393 if (!WorkingDir)

1394 return WorkingDir.getError();

1395

1396 return makeAbsolute(WorkingDir.get(), Path);

1397}

1398

1399std::error_code

1400RedirectingFileSystem::makeAbsolute(StringRef WorkingDir,

1402

1403

1404

1405

1406 if (!WorkingDir.empty() &&

1410 return std::error_code();

1411 }

1415 } else {

1416

1417

1420 }

1421

1422 std::string Result = std::string(WorkingDir);

1426 }

1427

1428

1429

1430

1431

1434

1435 return {};

1436}

1437

1439 std::error_code &EC) {

1442

1443 EC = makeAbsolute(Path);

1444 if (EC)

1445 return {};

1446

1448 if (!Result) {

1450 isFileNotFound(Result.getError()))

1451 return ExternalFS->dir_begin(Path, EC);

1452

1453 EC = Result.getError();

1454 return {};

1455 }

1456

1457

1459 if (!S) {

1461 isFileNotFound(S.getError(), Result->E))

1462 return ExternalFS->dir_begin(Dir, EC);

1463

1465 return {};

1466 }

1467

1468 if (!S->isDirectory()) {

1470 return {};

1471 }

1472

1473

1474

1476 std::error_code RedirectEC;

1477 if (auto ExtRedirect = Result->getExternalRedirect()) {

1478 auto RE = castRedirectingFileSystem::RemapEntry(Result->E);

1479 RedirectIter = ExternalFS->dir_begin(*ExtRedirect, RedirectEC);

1480

1481 if (!RE->useExternalName(UseExternalNames)) {

1482

1483 RedirectIter =

1485 std::string(Path), RedirectIter));

1486 }

1487 } else {

1488 auto DE = cast(Result->E);

1489 RedirectIter =

1491 Path, DE->contents_begin(), DE->contents_end(), RedirectEC));

1492 }

1493

1494 if (RedirectEC) {

1496 EC = RedirectEC;

1497 return {};

1498 }

1499 RedirectIter = {};

1500 }

1501

1503 EC = RedirectEC;

1504 return RedirectIter;

1505 }

1506

1507 std::error_code ExternalEC;

1508 directory_iterator ExternalIter = ExternalFS->dir_begin(Path, ExternalEC);

1509 if (ExternalEC) {

1511 EC = ExternalEC;

1512 return {};

1513 }

1514 ExternalIter = {};

1515 }

1516

1518 switch (Redirection) {

1522 break;

1526 break;

1527 default:

1529 }

1530

1532 std::make_shared(Iters, EC)};

1533 if (EC)

1534 return {};

1535 return Combined;

1536}

1537

1539 OverlayFileDir = Dir.str();

1540}

1541

1543 return OverlayFileDir;

1544}

1545

1549 } else {

1551 }

1552}

1553

1556 Redirection = Kind;

1557}

1558

1560 std::vector R;

1561 R.reserve(Roots.size());

1562 for (const auto &Root : Roots)

1563 R.push_back(Root->getName());

1564 return R;

1565}

1566

1568 unsigned IndentLevel) const {

1570 OS << "RedirectingFileSystem (UseExternalNames: "

1571 << (UseExternalNames ? "true" : "false") << ")\n";

1573 return;

1574

1575 for (const auto &Root : Roots)

1577

1579 OS << "ExternalFS:\n";

1581 IndentLevel + 1);

1582}

1583

1586 unsigned IndentLevel) const {

1588 OS << "'" << E->getName() << "'";

1589

1592 auto *DE = castRedirectingFileSystem::DirectoryEntry(E);

1593

1594 OS << "\n";

1595 for (std::unique_ptr &SubEntry :

1597 printEntry(OS, SubEntry.get(), IndentLevel + 1);

1598 break;

1599 }

1602 auto *RE = castRedirectingFileSystem::RemapEntry(E);

1603 OS << " -> '" << RE->getExternalContentsPath() << "'";

1604 switch (RE->getUseName()) {

1606 break;

1608 OS << " (UseExternalName: true)";

1609 break;

1611 OS << " (UseExternalName: false)";

1612 break;

1613 }

1614 OS << "\n";

1615 break;

1616 }

1617 }

1618}

1619

1621 if (ExternalFS) {

1622 Callback(*ExternalFS);

1623 ExternalFS->visitChildFileSystems(Callback);

1624 }

1625}

1626

1627

1630

1632

1633

1636 const auto *S = dyn_castyaml::ScalarNode(N);

1637

1638 if (!S) {

1639 error(N, "expected string");

1640 return false;

1641 }

1642 Result = S->getValue(Storage);

1643 return true;

1644 }

1645

1646

1647 bool parseScalarBool(yaml::Node *N, bool &Result) {

1650 if (!parseScalarString(N, Value, Storage))

1651 return false;

1652

1653 if (Value.equals_insensitive("true") || Value.equals_insensitive("on") ||

1654 Value.equals_insensitive("yes") || Value == "1") {

1655 Result = true;

1656 return true;

1657 } else if (Value.equals_insensitive("false") ||

1658 Value.equals_insensitive("off") ||

1659 Value.equals_insensitive("no") || Value == "0") {

1660 Result = false;

1661 return true;

1662 }

1663

1664 error(N, "expected boolean value");

1665 return false;

1666 }

1667

1668 std::optionalRedirectingFileSystem::RedirectKind

1672 if (!parseScalarString(N, Value, Storage))

1673 return std::nullopt;

1674

1675 if (Value.equals_insensitive("fallthrough")) {

1677 } else if (Value.equals_insensitive("fallback")) {

1679 } else if (Value.equals_insensitive("redirect-only")) {

1681 }

1682 return std::nullopt;

1683 }

1684

1685 std::optionalRedirectingFileSystem::RootRelativeKind

1689 if (!parseScalarString(N, Value, Storage))

1690 return std::nullopt;

1691 if (Value.equals_insensitive("cwd")) {

1693 } else if (Value.equals_insensitive("overlay-dir")) {

1695 }

1696 return std::nullopt;

1697 }

1698

1699 struct KeyStatus {

1700 bool Required;

1701 bool Seen = false;

1702

1703 KeyStatus(bool Required = false) : Required(Required) {}

1704 };

1705

1706 using KeyStatusPair = std::pair<StringRef, KeyStatus>;

1707

1708

1711 auto It = Keys.find(Key);

1712 if (It == Keys.end()) {

1713 error(KeyNode, "unknown key");

1714 return false;

1715 }

1716 KeyStatus &S = It->second;

1717 if (S.Seen) {

1718 error(KeyNode, Twine("duplicate key '") + Key + "'");

1719 return false;

1720 }

1721 S.Seen = true;

1722 return true;

1723 }

1724

1725

1727 for (const auto &I : Keys) {

1728 if (I.second.Required && I.second.Seen) {

1729 error(Obj, Twine("missing key '") + I.first + "'");

1730 return false;

1731 }

1732 }

1733 return true;

1734 }

1735

1736public:

1740 if (!ParentEntry) {

1741 for (const auto &Root : FS->Roots) {

1742 if (Name == Root->getName()) {

1743 ParentEntry = Root.get();

1744 return ParentEntry;

1745 }

1746 }

1747 } else {

1748 auto *DE = dyn_castRedirectingFileSystem::DirectoryEntry(ParentEntry);

1749 for (std::unique_ptrRedirectingFileSystem::Entry &Content :

1750 llvm::make_range(DE->contents_begin(), DE->contents_end())) {

1751 auto *DirContent =

1752 dyn_castRedirectingFileSystem::DirectoryEntry(Content.get());

1753 if (DirContent && Name == Content->getName())

1754 return DirContent;

1755 }

1756 }

1757

1758

1759 std::unique_ptrRedirectingFileSystem::Entry E =

1760 std::make_uniqueRedirectingFileSystem::DirectoryEntry(

1762 std::chrono::system_clock::now(), 0, 0, 0,

1764

1765 if (!ParentEntry) {

1766 FS->Roots.push_back(std::move(E));

1767 ParentEntry = FS->Roots.back().get();

1768 return ParentEntry;

1769 }

1770

1771 auto *DE = castRedirectingFileSystem::DirectoryEntry(ParentEntry);

1772 DE->addContent(std::move(E));

1773 return DE->getLastContent();

1774 }

1775

1776private:

1781 switch (SrcE->getKind()) {

1783 auto *DE = castRedirectingFileSystem::DirectoryEntry(SrcE);

1784

1785

1786

1787 if (Name.empty())

1789 for (std::unique_ptrRedirectingFileSystem::Entry &SubEntry :

1791 uniqueOverlayTree(FS, SubEntry.get(), NewParentE);

1792 break;

1793 }

1795 assert(NewParentE && "Parent entry must exist");

1796 auto *DR = castRedirectingFileSystem::DirectoryRemapEntry(SrcE);

1797 auto *DE = castRedirectingFileSystem::DirectoryEntry(NewParentE);

1798 DE->addContent(

1799 std::make_uniqueRedirectingFileSystem::DirectoryRemapEntry(

1800 Name, DR->getExternalContentsPath(), DR->getUseName()));

1801 break;

1802 }

1804 assert(NewParentE && "Parent entry must exist");

1805 auto *FE = castRedirectingFileSystem::FileEntry(SrcE);

1806 auto *DE = castRedirectingFileSystem::DirectoryEntry(NewParentE);

1807 DE->addContent(std::make_uniqueRedirectingFileSystem::FileEntry(

1808 Name, FE->getExternalContentsPath(), FE->getUseName()));

1809 break;

1810 }

1811 }

1812 }

1813

1814 std::unique_ptrRedirectingFileSystem::Entry

1816 auto *M = dyn_castyaml::MappingNode(N);

1817 if (!M) {

1818 error(N, "expected mapping node for file or directory entry");

1819 return nullptr;

1820 }

1821

1822 KeyStatusPair Fields[] = {

1823 KeyStatusPair("name", true),

1824 KeyStatusPair("type", true),

1825 KeyStatusPair("contents", false),

1826 KeyStatusPair("external-contents", false),

1827 KeyStatusPair("use-external-name", false),

1828 };

1829

1831

1832 enum { CF_NotSet, CF_List, CF_External } ContentsField = CF_NotSet;

1833 std::vector<std::unique_ptrRedirectingFileSystem::Entry>

1834 EntryArrayContents;

1837 yaml::Node *NameValueNode = nullptr;

1840

1841 for (auto &I : *M) {

1843

1844

1846 if (!parseScalarString(I.getKey(), Key, Buffer))

1847 return nullptr;

1848

1849 if (!checkDuplicateOrUnknownKey(I.getKey(), Key, Keys))

1850 return nullptr;

1851

1853 if (Key == "name") {

1854 if (!parseScalarString(I.getValue(), Value, Buffer))

1855 return nullptr;

1856

1857 NameValueNode = I.getValue();

1858

1859

1860 Name = canonicalize(Value).str();

1861 } else if (Key == "type") {

1862 if (!parseScalarString(I.getValue(), Value, Buffer))

1863 return nullptr;

1864 if (Value == "file")

1866 else if (Value == "directory")

1868 else if (Value == "directory-remap")

1870 else {

1871 error(I.getValue(), "unknown value for 'type'");

1872 return nullptr;

1873 }

1874 } else if (Key == "contents") {

1875 if (ContentsField != CF_NotSet) {

1877 "entry already has 'contents' or 'external-contents'");

1878 return nullptr;

1879 }

1880 ContentsField = CF_List;

1881 auto *Contents = dyn_castyaml::SequenceNode(I.getValue());

1882 if (!Contents) {

1883

1884 error(I.getValue(), "expected array");

1885 return nullptr;

1886 }

1887

1888 for (auto &I : *Contents) {

1889 if (std::unique_ptrRedirectingFileSystem::Entry E =

1890 parseEntry(&I, FS, false))

1891 EntryArrayContents.push_back(std::move(E));

1892 else

1893 return nullptr;

1894 }

1895 } else if (Key == "external-contents") {

1896 if (ContentsField != CF_NotSet) {

1898 "entry already has 'contents' or 'external-contents'");

1899 return nullptr;

1900 }

1901 ContentsField = CF_External;

1902 if (!parseScalarString(I.getValue(), Value, Buffer))

1903 return nullptr;

1904

1906 if (FS->IsRelativeOverlay) {

1907 FullPath = FS->getOverlayFileDir();

1909 "External contents prefix directory must exist");

1911 } else {

1912 FullPath = Value;

1913 }

1914

1915

1916

1917 FullPath = canonicalize(FullPath);

1918 ExternalContentsPath = FullPath.str();

1919 } else if (Key == "use-external-name") {

1920 bool Val;

1921 if (!parseScalarBool(I.getValue(), Val))

1922 return nullptr;

1925 } else {

1927 }

1928 }

1929

1930 if (Stream.failed())

1931 return nullptr;

1932

1933

1934 if (ContentsField == CF_NotSet) {

1935 error(N, "missing key 'contents' or 'external-contents'");

1936 return nullptr;

1937 }

1938 if (!checkMissingKeys(N, Keys))

1939 return nullptr;

1940

1941

1944 error(N, "'use-external-name' is not supported for 'directory' entries");

1945 return nullptr;

1946 }

1947

1949 ContentsField == CF_List) {

1950 error(N, "'contents' is not supported for 'directory-remap' entries");

1951 return nullptr;

1952 }

1953

1955 if (IsRootEntry) {

1956

1957

1963 } else {

1964

1965

1966

1967 std::error_code EC;

1968 if (FS->RootRelative ==

1970 StringRef FullPath = FS->getOverlayFileDir();

1971 assert(!FullPath.empty() && "Overlay file directory must exist");

1972 EC = FS->makeAbsolute(FullPath, Name);

1974 } else {

1976 }

1977 if (EC) {

1978 assert(NameValueNode && "Name presence should be checked earlier");

1980 NameValueNode,

1981 "entry with relative path at the root level is not discoverable");

1982 return nullptr;

1983 }

1987 }

1988

1989

1990

1994 }

1995

1996

1999 while (Trimmed.size() > RootPathLen &&

2001 Trimmed = Trimmed.slice(0, Trimmed.size() - 1);

2002

2003

2005

2006 std::unique_ptrRedirectingFileSystem::Entry Result;

2007 switch (Kind) {

2009 Result = std::make_uniqueRedirectingFileSystem::FileEntry(

2010 LastComponent, std::move(ExternalContentsPath), UseExternalName);

2011 break;

2013 Result = std::make_uniqueRedirectingFileSystem::DirectoryRemapEntry(

2014 LastComponent, std::move(ExternalContentsPath), UseExternalName);

2015 break;

2017 Result = std::make_uniqueRedirectingFileSystem::DirectoryEntry(

2018 LastComponent, std::move(EntryArrayContents),

2021 break;

2022 }

2023

2025 if (Parent.empty())

2027

2028

2031 I != E; ++I) {

2032 std::vector<std::unique_ptrRedirectingFileSystem::Entry> Entries;

2033 Entries.push_back(std::move(Result));

2034 Result = std::make_uniqueRedirectingFileSystem::DirectoryEntry(

2035 *I, std::move(Entries),

2038 }

2040 }

2041

2042public:

2044

2045

2047 auto *Top = dyn_castyaml::MappingNode(Root);

2048 if (!Top) {

2049 error(Root, "expected mapping node");

2050 return false;

2051 }

2052

2053 KeyStatusPair Fields[] = {

2054 KeyStatusPair("version", true),

2055 KeyStatusPair("case-sensitive", false),

2056 KeyStatusPair("use-external-names", false),

2057 KeyStatusPair("root-relative", false),

2058 KeyStatusPair("overlay-relative", false),

2059 KeyStatusPair("fallthrough", false),

2060 KeyStatusPair("redirecting-with", false),

2061 KeyStatusPair("roots", true),

2062 };

2063

2065 std::vector<std::unique_ptrRedirectingFileSystem::Entry> RootEntries;

2066

2067

2068 for (auto &I : *Top) {

2071 if (!parseScalarString(I.getKey(), Key, KeyBuffer))

2072 return false;

2073

2074 if (!checkDuplicateOrUnknownKey(I.getKey(), Key, Keys))

2075 return false;

2076

2077 if (Key == "roots") {

2078 auto *Roots = dyn_castyaml::SequenceNode(I.getValue());

2079 if (!Roots) {

2080 error(I.getValue(), "expected array");

2081 return false;

2082 }

2083

2084 for (auto &I : *Roots) {

2085 if (std::unique_ptrRedirectingFileSystem::Entry E =

2086 parseEntry(&I, FS, true))

2087 RootEntries.push_back(std::move(E));

2088 else

2089 return false;

2090 }

2091 } else if (Key == "version") {

2094 if (!parseScalarString(I.getValue(), VersionString, Storage))

2095 return false;

2098 error(I.getValue(), "expected integer");

2099 return false;

2100 }

2102 error(I.getValue(), "invalid version number");

2103 return false;

2104 }

2106 error(I.getValue(), "version mismatch, expected 0");

2107 return false;

2108 }

2109 } else if (Key == "case-sensitive") {

2110 if (!parseScalarBool(I.getValue(), FS->CaseSensitive))

2111 return false;

2112 } else if (Key == "overlay-relative") {

2113 if (!parseScalarBool(I.getValue(), FS->IsRelativeOverlay))

2114 return false;

2115 } else if (Key == "use-external-names") {

2116 if (!parseScalarBool(I.getValue(), FS->UseExternalNames))

2117 return false;

2118 } else if (Key == "fallthrough") {

2119 if (Keys["redirecting-with"].Seen) {

2121 "'fallthrough' and 'redirecting-with' are mutually exclusive");

2122 return false;

2123 }

2124

2125 bool ShouldFallthrough = false;

2126 if (!parseScalarBool(I.getValue(), ShouldFallthrough))

2127 return false;

2128

2129 if (ShouldFallthrough) {

2131 } else {

2133 }

2134 } else if (Key == "redirecting-with") {

2135 if (Keys["fallthrough"].Seen) {

2137 "'fallthrough' and 'redirecting-with' are mutually exclusive");

2138 return false;

2139 }

2140

2141 if (auto Kind = parseRedirectKind(I.getValue())) {

2142 FS->Redirection = *Kind;

2143 } else {

2144 error(I.getValue(), "expected valid redirect kind");

2145 return false;

2146 }

2147 } else if (Key == "root-relative") {

2148 if (auto Kind = parseRootRelativeKind(I.getValue())) {

2149 FS->RootRelative = *Kind;

2150 } else {

2151 error(I.getValue(), "expected valid root-relative kind");

2152 return false;

2153 }

2154 } else {

2156 }

2157 }

2158

2159 if (Stream.failed())

2160 return false;

2161

2162 if (!checkMissingKeys(Top, Keys))

2163 return false;

2164

2165

2166

2167

2168 for (auto &E : RootEntries)

2169 uniqueOverlayTree(FS, E.get());

2170

2171 return true;

2172 }

2173};

2174

2175std::unique_ptr

2178 StringRef YAMLFilePath, void *DiagContext,

2181 yaml::Stream Stream(Buffer->getMemBufferRef(), SM);

2182

2186 if (DI == Stream.end() || !Root) {

2188 return nullptr;

2189 }

2190

2192

2193 std::unique_ptr FS(

2195

2196 if (!YAMLFilePath.empty()) {

2197

2198

2199

2200

2201

2202

2203

2204

2207 assert(!EC && "Overlay dir final path must be absolute");

2208 (void)EC;

2209 FS->setOverlayFileDir(OverlayAbsDir);

2210 }

2211

2212 if (P.parse(Root, FS.get()))

2213 return nullptr;

2214

2215 return FS;

2216}

2217

2219 ArrayRef<std::pair<std::string, std::string>> RemappedFiles,

2220 bool UseExternalNames, FileSystem &ExternalFS) {

2221 std::unique_ptr FS(

2223 FS->UseExternalNames = UseExternalNames;

2224

2226

2227 for (auto &Mapping : llvm::reverse(RemappedFiles)) {

2230 {

2232 (void)EC;

2233 assert(!EC && "Could not make absolute path");

2234 }

2235

2236

2237

2239 if (ToEntry)

2240 continue;

2241

2242

2247 I != E; ++I) {

2249 Parent);

2250 }

2251 assert(Parent && "File without a directory?");

2252 {

2254 (void)EC;

2255 assert(!EC && "Could not make absolute path");

2256 }

2257

2258

2259 auto NewFile = std::make_uniqueRedirectingFileSystem::FileEntry(

2263 ToEntry = NewFile.get();

2264 castRedirectingFileSystem::DirectoryEntry(Parent)->addContent(

2265 std::move(NewFile));

2266 }

2267

2268 return FS;

2269}

2270

2273 : E(E) {

2275

2276

2277

2278 if (auto *DRE = dyn_castRedirectingFileSystem::DirectoryRemapEntry(E)) {

2281 getExistingStyle(DRE->getExternalContentsPath()));

2282 ExternalRedirect = std::string(Redirect);

2283 }

2284}

2285

2288 Result.clear();

2289 for (Entry *Parent : Parents)

2292}

2293

2294std::error_code RedirectingFileSystem::makeCanonicalForLookup(

2296 if (std::error_code EC = makeAbsolute(Path))

2297 return EC;

2298

2300 canonicalize(StringRef(Path.data(), Path.size()));

2301 if (CanonicalPath.empty())

2303

2304 Path.assign(CanonicalPath.begin(), CanonicalPath.end());

2305 return {};

2306}

2307

2311 if (std::error_code EC = makeCanonicalForLookup(CanonicalPath))

2312 return EC;

2313

2314

2316 HasBeenUsed = true;

2317

2321 for (const auto &Root : Roots) {

2323 lookupPathImpl(Start, End, Root.get(), Entries);

2324 if (UsageTrackingActive && Result && isa(Result->E))

2325 HasBeenUsed = true;

2327 Result->Parents = std::move(Entries);

2328 return Result;

2329 }

2330 }

2332}

2333

2335RedirectingFileSystem::lookupPathImpl(

2341 "Paths should not contain traversal components");

2342

2344

2345

2346 if (!FromName.empty()) {

2347 if (!pathComponentMatches(*Start, FromName))

2349

2350 ++Start;

2351

2352 if (Start == End) {

2353

2354 return LookupResult(From, Start, End);

2355 }

2356 }

2357

2358 if (isaRedirectingFileSystem::FileEntry(From))

2360

2361 if (isaRedirectingFileSystem::DirectoryRemapEntry(From))

2362 return LookupResult(From, Start, End);

2363

2364 auto *DE = castRedirectingFileSystem::DirectoryEntry(From);

2365 for (const std::unique_ptrRedirectingFileSystem::Entry &DirEntry :

2366 llvm::make_range(DE->contents_begin(), DE->contents_end())) {

2367 Entries.push_back(From);

2369 lookupPathImpl(Start, End, DirEntry.get(), Entries);

2371 return Result;

2372 Entries.pop_back();

2373 }

2374

2376}

2377

2379 bool UseExternalNames,

2380 Status ExternalStatus) {

2381

2382

2384 return ExternalStatus;

2385

2386 Status S = ExternalStatus;

2387 if (!UseExternalNames)

2389 else

2391 return S;

2392}

2393

2395 const Twine &LookupPath, const Twine &OriginalPath,

2397 if (std::optional ExtRedirect = Result.getExternalRedirect()) {

2399 if (std::error_code EC = makeAbsolute(RemappedPath))

2400 return EC;

2401

2403 if (!S)

2404 return S;

2406 auto *RE = castRedirectingFileSystem::RemapEntry(Result.E);

2408 RE->useExternalName(UseExternalNames), *S);

2409 }

2410

2411 auto *DE = castRedirectingFileSystem::DirectoryEntry(Result.E);

2413}

2414

2416RedirectingFileSystem::getExternalStatus(const Twine &LookupPath,

2417 const Twine &OriginalPath) const {

2418 auto Result = ExternalFS->status(LookupPath);

2419

2420

2421

2422 if (!Result || Result->ExposesExternalVFSPath)

2425}

2426

2429 OriginalPath.toVector(Path);

2430

2431 if (std::error_code EC = makeAbsolute(Path))

2432 return EC;

2433

2435

2436

2437 ErrorOr S = getExternalStatus(Path, OriginalPath);

2438 if (S)

2439 return S;

2440 }

2441

2443 if (!Result) {

2444

2445

2447 isFileNotFound(Result.getError()))

2448 return getExternalStatus(Path, OriginalPath);

2449 return Result.getError();

2450 }

2451

2452 ErrorOr S = status(Path, OriginalPath, *Result);

2454 isFileNotFound(S.getError(), Result->E)) {

2455

2456

2457

2458 return getExternalStatus(Path, OriginalPath);

2459 }

2460

2461 return S;

2462}

2463

2466 OriginalPath.toVector(Path);

2467

2468 if (makeAbsolute(Path))

2469 return false;

2470

2472

2473

2474 if (ExternalFS->exists(Path))

2475 return true;

2476 }

2477

2479 if (!Result) {

2480

2481

2483 isFileNotFound(Result.getError()))

2484 return ExternalFS->exists(Path);

2485 return false;

2486 }

2487

2488 std::optional ExtRedirect = Result->getExternalRedirect();

2489 if (!ExtRedirect) {

2490 assert(isaRedirectingFileSystem::DirectoryEntry(Result->E));

2491 return true;

2492 }

2493

2495 if (makeAbsolute(RemappedPath))

2496 return false;

2497

2498 if (ExternalFS->exists(RemappedPath))

2499 return true;

2500

2502

2503

2504

2505 return ExternalFS->exists(Path);

2506 }

2507

2508 return false;

2509}

2510

2511namespace {

2512

2513

2514class FileWithFixedStatus : public File {

2515 std::unique_ptr InnerFile;

2517

2518public:

2519 FileWithFixedStatus(std::unique_ptr InnerFile, Status S)

2520 : InnerFile(std::move(InnerFile)), S(std::move(S)) {}

2521

2524

2525 getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,

2526 bool IsVolatile) override {

2527 return InnerFile->getBuffer(Name, FileSize, RequiresNullTerminator,

2528 IsVolatile);

2529 }

2530

2531 std::error_code close() override { return InnerFile->close(); }

2532

2533 void setPath(const Twine &Path) override { S = S.copyWithNewName(S, Path); }

2534};

2535

2536}

2537

2540

2541

2542 if (!Result || (*Result)->status()->ExposesExternalVFSPath)

2543 return Result;

2544

2546 auto Name = F->get()->getName();

2547 if (Name && Name.get() != P.str())

2548 F->get()->setPath(P);

2549 return F;

2550}

2551

2555 OriginalPath.toVector(Path);

2556

2557 if (std::error_code EC = makeAbsolute(Path))

2558 return EC;

2559

2561

2562

2563 auto F = File::getWithPath(ExternalFS->openFileForRead(Path), OriginalPath);

2564 if (F)

2565 return F;

2566 }

2567

2569 if (!Result) {

2570

2571

2573 isFileNotFound(Result.getError()))

2574 return File::getWithPath(ExternalFS->openFileForRead(Path), OriginalPath);

2575 return Result.getError();

2576 }

2577

2578 if (!Result->getExternalRedirect())

2580

2581 StringRef ExtRedirect = *Result->getExternalRedirect();

2583 if (std::error_code EC = makeAbsolute(RemappedPath))

2584 return EC;

2585

2586 auto *RE = castRedirectingFileSystem::RemapEntry(Result->E);

2587

2588 auto ExternalFile =

2589 File::getWithPath(ExternalFS->openFileForRead(RemappedPath), ExtRedirect);

2590 if (!ExternalFile) {

2592 isFileNotFound(ExternalFile.getError(), Result->E)) {

2593

2594

2595

2596 return File::getWithPath(ExternalFS->openFileForRead(Path), OriginalPath);

2597 }

2598 return ExternalFile;

2599 }

2600

2601 auto ExternalStatus = (*ExternalFile)->status();

2602 if (!ExternalStatus)

2603 return ExternalStatus.getError();

2604

2605

2606

2608 OriginalPath, RE->useExternalName(UseExternalNames), *ExternalStatus);

2609 return std::unique_ptr(

2610 std::make_unique(std::move(*ExternalFile), S));

2611}

2612

2613std::error_code

2617 OriginalPath.toVector(Path);

2618

2619 if (std::error_code EC = makeAbsolute(Path))

2620 return EC;

2621

2623

2624

2625 std::error_code EC = ExternalFS->getRealPath(Path, Output);

2626 if (!EC)

2627 return EC;

2628 }

2629

2631 if (!Result) {

2632

2633

2635 isFileNotFound(Result.getError()))

2636 return ExternalFS->getRealPath(Path, Output);

2637 return Result.getError();

2638 }

2639

2640

2641

2642 if (auto ExtRedirect = Result->getExternalRedirect()) {

2643 auto P = ExternalFS->getRealPath(*ExtRedirect, Output);

2645 isFileNotFound(P, Result->E)) {

2646

2647

2648

2649 return ExternalFS->getRealPath(Path, Output);

2650 }

2651 return P;

2652 }

2653

2654

2655

2657 Result->getPath(Output);

2658 return {};

2659 }

2661}

2662

2663std::unique_ptr

2666 StringRef YAMLFilePath, void *DiagContext,

2669 YAMLFilePath, DiagContext,

2670 std::move(ExternalFS));

2671}

2672

2676 auto Kind = SrcE->getKind();

2678 auto *DE = dyn_castRedirectingFileSystem::DirectoryEntry(SrcE);

2679 assert(DE && "Must be a directory");

2680 for (std::unique_ptrRedirectingFileSystem::Entry &SubEntry :

2681 llvm::make_range(DE->contents_begin(), DE->contents_end())) {

2682 Path.push_back(SubEntry->getName());

2684 Path.pop_back();

2685 }

2686 return;

2687 }

2688

2690 auto *DR = dyn_castRedirectingFileSystem::DirectoryRemapEntry(SrcE);

2691 assert(DR && "Must be a directory remap");

2693 for (auto &Comp : Path)

2695 Entries.push_back(

2697 return;

2698 }

2699

2701 auto *FE = dyn_castRedirectingFileSystem::FileEntry(SrcE);

2702 assert(FE && "Must be a file");

2704 for (auto &Comp : Path)

2706 Entries.push_back(YAMLVFSEntry(VPath.c_str(), FE->getExternalContentsPath()));

2707}

2708

2713 void *DiagContext,

2716 std::move(Buffer), DiagHandler, YAMLFilePath, DiagContext,

2717 std::move(ExternalFS));

2718 if (!VFS)

2719 return;

2721 VFS->lookupPath("/");

2722 if (!RootResult)

2723 return;

2726 getVFSEntries(RootResult->E, Components, CollectedEntries);

2727}

2728

2730 static std::atomic UID;

2731 unsigned ID = ++UID;

2732

2733

2734 return UniqueID(std::numeric_limits<uint64_t>::max(), ID);

2735}

2736

2737void YAMLVFSWriter::addEntry(StringRef VirtualPath, StringRef RealPath,

2738 bool IsDirectory) {

2742 Mappings.emplace_back(VirtualPath, RealPath, IsDirectory);

2743}

2744

2746 addEntry(VirtualPath, RealPath, false);

2747}

2748

2751 addEntry(VirtualPath, RealPath, true);

2752}

2753

2754namespace {

2755

2756class JSONWriter {

2759

2760 unsigned getDirIndent() { return 4 * DirStack.size(); }

2761 unsigned getFileIndent() { return 4 * (DirStack.size() + 1); }

2764 void startDirectory(StringRef Path);

2765 void endDirectory();

2767

2768public:

2770

2772 std::optional UseExternalNames,

2773 std::optional IsCaseSensitive,

2774 std::optional IsOverlayRelative, StringRef OverlayDir);

2775};

2776

2777}

2778

2781

2782

2785 IParent != EParent && IChild != EChild; ++IParent, ++IChild) {

2786 if (*IParent != *IChild)

2787 return false;

2788 }

2789

2790 return IParent == EParent;

2791}

2792

2795 assert(containedIn(Parent, Path));

2796 return Path.substr(Parent.size() + 1);

2797}

2798

2799void JSONWriter::startDirectory(StringRef Path) {

2801 DirStack.empty() ? Path : containedPart(DirStack.back(), Path);

2803 unsigned Indent = getDirIndent();

2805 OS.indent(Indent + 2) << "'type': 'directory',\n";

2807 OS.indent(Indent + 2) << "'contents': [\n";

2808}

2809

2810void JSONWriter::endDirectory() {

2811 unsigned Indent = getDirIndent();

2812 OS.indent(Indent + 2) << "]\n";

2814

2816}

2817

2819 unsigned Indent = getFileIndent();

2821 OS.indent(Indent + 2) << "'type': 'file',\n";

2823 OS.indent(Indent + 2) << "'external-contents': \""

2826}

2827

2829 std::optional UseExternalNames,

2830 std::optional IsCaseSensitive,

2831 std::optional IsOverlayRelative,

2834

2835 OS << "{\n"

2836 " 'version': 0,\n";

2837 if (IsCaseSensitive)

2838 OS << " 'case-sensitive': '" << (*IsCaseSensitive ? "true" : "false")

2839 << "',\n";

2840 if (UseExternalNames)

2841 OS << " 'use-external-names': '" << (*UseExternalNames ? "true" : "false")

2842 << "',\n";

2843 bool UseOverlayRelative = false;

2844 if (IsOverlayRelative) {

2845 UseOverlayRelative = *IsOverlayRelative;

2846 OS << " 'overlay-relative': '" << (UseOverlayRelative ? "true" : "false")

2847 << "',\n";

2848 }

2849 OS << " 'roots': [\n";

2850

2851 if (!Entries.empty()) {

2853

2854 startDirectory(

2856 );

2857

2859 if (UseOverlayRelative) {

2861 "Overlay dir must be contained in RPath");

2863 }

2864

2865 bool IsCurrentDirEmpty = true;

2866 if (Entry.IsDirectory) {

2868 IsCurrentDirEmpty = false;

2869 }

2870

2871 for (const auto &Entry : Entries.slice(1)) {

2874 if (Dir == DirStack.back()) {

2875 if (!IsCurrentDirEmpty) {

2876 OS << ",\n";

2877 }

2878 } else {

2879 bool IsDirPoppedFromStack = false;

2880 while (!DirStack.empty() && !containedIn(DirStack.back(), Dir)) {

2881 OS << "\n";

2882 endDirectory();

2883 IsDirPoppedFromStack = true;

2884 }

2885 if (IsDirPoppedFromStack || !IsCurrentDirEmpty) {

2886 OS << ",\n";

2887 }

2888 startDirectory(Dir);

2889 IsCurrentDirEmpty = true;

2890 }

2892 if (UseOverlayRelative) {

2894 "Overlay dir must be contained in RPath");

2896 }

2897 if (Entry.IsDirectory) {

2899 IsCurrentDirEmpty = false;

2900 }

2901 }

2902

2903 while (!DirStack.empty()) {

2904 OS << "\n";

2905 endDirectory();

2906 }

2907 OS << "\n";

2908 }

2909

2910 OS << " ]\n"

2911 << "}\n";

2912}

2913

2916 return LHS.VPath < RHS.VPath;

2917 });

2918

2919 JSONWriter(OS).write(Mappings, UseExternalNames, IsCaseSensitive,

2921}

2922

2924 FileSystem &FS_, const Twine &Path, std::error_code &EC)

2925 : FS(&FS_) {

2928 State = std::make_shareddetail::RecDirIterState();

2929 State->Stack.push_back(I);

2930 }

2931}

2932

2935 assert(FS && State && !State->Stack.empty() && "incrementing past end");

2936 assert(!State->Stack.back()->path().empty() && "non-canonical end iterator");

2938

2939 if (State->HasNoPushRequest)

2940 State->HasNoPushRequest = false;

2941 else {

2944 FS->dir_begin(State->Stack.back()->path(), EC);

2945 if (I != End) {

2946 State->Stack.push_back(I);

2947 return *this;

2948 }

2949 }

2950 }

2951

2952 while (!State->Stack.empty() && State->Stack.back().increment(EC) == End)

2953 State->Stack.pop_back();

2954

2955 if (State->Stack.empty())

2956 State.reset();

2957

2958 return *this;

2959}

2960

2962 unsigned IndentLevel) const {

2963 printIndent(OS, IndentLevel);

2964 OS << "TracingFileSystem\n";

2965 if (Type == PrintType::Summary)

2966 return;

2967

2968 printIndent(OS, IndentLevel);

2970 printIndent(OS, IndentLevel);

2972 printIndent(OS, IndentLevel);

2974 printIndent(OS, IndentLevel);

2976 printIndent(OS, IndentLevel);

2978 printIndent(OS, IndentLevel);

2980

2981 if (Type == PrintType::Contents)

2982 Type = PrintType::Summary;

2983 getUnderlyingFS().print(OS, Type, IndentLevel + 1);

2984}

2985

BlockVerifier::State From

static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")

static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")

This file defines the DenseMap class.

Provides ErrorOr smart pointer.

static void makeAbsolute(SmallVectorImpl< char > &Path)

Make Path absolute.

This file defines the RefCountedBase, ThreadSafeRefCountedBase, and IntrusiveRefCntPtr classes.

static StringRef getName(Value *V)

assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())

This file defines the SmallString class.

This file defines the SmallVector class.

StringSet - A set-like wrapper for the StringMap.

static void DiagHandler(const SMDiagnostic &Diag, void *Context)

static void getVFSEntries(RedirectingFileSystem::Entry *SrcE, SmallVectorImpl< StringRef > &Path, SmallVectorImpl< YAMLVFSEntry > &Entries)

static Status getRedirectedFileStatus(const Twine &OriginalPath, bool UseExternalNames, Status ExternalStatus)

static bool pathHasTraversal(StringRef Path)

static bool isTraversalComponent(StringRef Component)

Defines the virtual file system interface vfs::FileSystem.

static unsigned getSize(unsigned Kind)

ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...

iterator find(const_arg_type_t< KeyT > Val)

Represents either an error or a value T.

std::error_code getError() const

Tagged union holding either a T or a Error.

Error takeError()

Take ownership of the stored error.

A smart pointer to a reference-counted object that inherits from RefCountedBase or ThreadSafeRefCount...

This interface provides simple read-only access to a block of memory, and provides simple methods for...

static ErrorOr< std::unique_ptr< MemoryBuffer > > getOpenFile(sys::fs::file_t FD, const Twine &Filename, uint64_t FileSize, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)

Given an already-open file descriptor, read the file and return a MemoryBuffer.

static std::unique_ptr< MemoryBuffer > getMemBuffer(StringRef InputData, StringRef BufferName="", bool RequiresNullTerminator=true)

Open the specified memory range as a MemoryBuffer.

virtual StringRef getBufferIdentifier() const

Return an identifier for this buffer, typically the filename it was read from.

StringRef getBuffer() const

Represents a location in source code.

SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...

StringRef str() const

Explicit conversion to StringRef.

This class consists of common code factored out of the SmallVector class to reduce code duplication b...

void push_back(const T &Elt)

This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.

This owns the files read by a parser, handles include stacks, and handles diagnostic wrangling.

void PrintMessage(raw_ostream &OS, SMLoc Loc, DiagKind Kind, const Twine &Msg, ArrayRef< SMRange > Ranges={}, ArrayRef< SMFixIt > FixIts={}, bool ShowColors=true) const

Emit a message about the specified location with the specified string.

void(*)(const SMDiagnostic &, void *Context) DiagHandlerTy

Clients that want to handle their own diagnostics in a custom way can register a function pointer+con...

void setDiagHandler(DiagHandlerTy DH, void *Ctx=nullptr)

Specify a diagnostic handler to be invoked every time PrintMessage is called.

StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...

StringRef - Represent a constant reference to a string, i.e.

bool getAsInteger(unsigned Radix, T &Result) const

Parse the current string as an integer of the specified radix.

std::string str() const

str - Get the contents as an std::string.

constexpr StringRef substr(size_t Start, size_t N=npos) const

Return a reference to the substring from [Start, Start + N).

bool starts_with(StringRef Prefix) const

Check if this string starts with the given Prefix.

constexpr bool empty() const

empty - Check if the string is empty.

char back() const

back - Get the last character in the string.

StringRef slice(size_t Start, size_t End) const

Return a reference to the substring from [Start, End).

constexpr size_t size() const

size - Get the string size.

StringSet - A wrapper for StringMap that provides set-like functionality.

std::pair< typename Base::iterator, bool > insert(StringRef key)

Target - Wrapper for Target specific information.

Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...

std::string str() const

Return the twine contents as a std::string.

void toVector(SmallVectorImpl< char > &Out) const

Append the concatenated string into the given SmallString or SmallVector.

The instances of the Type class are immutable: once they are created, they are never changed.

void print(raw_ostream &O, bool IsForDebug=false, bool NoDetails=false) const

Print the current type.

LLVM Value Representation.

An efficient, type-erasing, non-owning reference to a callable.

An opaque object representing a hash code.

This class implements an extremely fast bulk output stream that can only output to a stream.

raw_ostream & indent(unsigned NumSpaces)

indent - Insert 'NumSpaces' spaces.

const std::string & path() const

directory_iterator - Iterates through the entries in path.

directory_iterator & increment(std::error_code &ec)

Represents the result of a call to sys::fs::status().

The virtual file system interface.

virtual llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const =0

Get the working directory of this file system.

virtual bool exists(const Twine &Path)

Check whether Path exists.

virtual llvm::ErrorOr< std::unique_ptr< File > > openFileForReadBinary(const Twine &Path)

Get a File object for the binary file at Path, if one exists.

virtual std::error_code makeAbsolute(SmallVectorImpl< char > &Path) const

Make Path an absolute path.

virtual llvm::ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path)=0

Get a File object for the text file at Path, if one exists.

virtual std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output)

Gets real path of Path e.g.

void printIndent(raw_ostream &OS, unsigned IndentLevel) const

LLVM_DUMP_METHOD void dump() const

void print(raw_ostream &OS, PrintType Type=PrintType::Contents, unsigned IndentLevel=0) const

llvm::ErrorOr< std::unique_ptr< llvm::MemoryBuffer > > getBufferForFile(const Twine &Name, int64_t FileSize=-1, bool RequiresNullTerminator=true, bool IsVolatile=false, bool IsText=true)

This is a convenience method that opens a file, gets its content and then closes the file.

llvm::ErrorOr< bool > equivalent(const Twine &A, const Twine &B)

virtual std::error_code isLocal(const Twine &Path, bool &Result)

Is the file mounted on a local filesystem?

virtual llvm::ErrorOr< Status > status(const Twine &Path)=0

Get the status of the entry at Path, if one exists.

static ErrorOr< std::unique_ptr< File > > getWithPath(ErrorOr< std::unique_ptr< File > > Result, const Twine &P)

virtual ~File()

Destroy the file after closing it (if open).

Adaptor from InMemoryDir::iterator to directory_iterator.

DirIterator(const InMemoryFileSystem *FS, const detail::InMemoryDirectory &Dir, std::string RequestedDirName)

std::error_code increment() override

Sets CurrentEntry to the next entry in the directory on success, to directory_entry() at end,...

An in-memory file system.

std::error_code isLocal(const Twine &Path, bool &Result) override

directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override

std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output) override

Canonicalizes Path by combining with the current working directory and normalizing the path (e....

~InMemoryFileSystem() override

static constexpr size_t MaxSymlinkDepth

Arbitrary max depth to search through symlinks.

InMemoryFileSystem(bool UseNormalizedPaths=true)

bool useNormalizedPaths() const

Return true if this file system normalizes . and .. in paths.

void printImpl(raw_ostream &OS, PrintType Type, unsigned IndentLevel) const override

llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const override

bool addHardLink(const Twine &NewLink, const Twine &Target)

Add a hard link to a file.

std::string toString() const

bool addFileNoOwn(const Twine &Path, time_t ModificationTime, const llvm::MemoryBufferRef &Buffer, std::optional< uint32_t > User=std::nullopt, std::optional< uint32_t > Group=std::nullopt, std::optional< llvm::sys::fs::file_type > Type=std::nullopt, std::optional< llvm::sys::fs::perms > Perms=std::nullopt)

Add a buffer to the VFS with a path.

bool addSymbolicLink(const Twine &NewLink, const Twine &Target, time_t ModificationTime, std::optional< uint32_t > User=std::nullopt, std::optional< uint32_t > Group=std::nullopt, std::optional< llvm::sys::fs::perms > Perms=std::nullopt)

Add a symbolic link.

std::error_code setCurrentWorkingDirectory(const Twine &Path) override

llvm::ErrorOr< Status > status(const Twine &Path) override

llvm::ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path) override

directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override

void visitChildFileSystems(VisitCallbackTy Callback) override

llvm::ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path) override

std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output) override

std::error_code setCurrentWorkingDirectory(const Twine &Path) override

void pushOverlay(IntrusiveRefCntPtr< FileSystem > FS)

Pushes a file system on top of the stack.

OverlayFileSystem(IntrusiveRefCntPtr< FileSystem > Base)

llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const override

iterator overlays_end()

Get an iterator pointing one-past the least recently added file system.

std::error_code isLocal(const Twine &Path, bool &Result) override

bool exists(const Twine &Path) override

llvm::ErrorOr< Status > status(const Twine &Path) override

iterator overlays_begin()

Get an iterator pointing to the most recently added file system.

FileSystemList::reverse_iterator iterator

void printImpl(raw_ostream &OS, PrintType Type, unsigned IndentLevel) const override

Directory iterator implementation for RedirectingFileSystem's directory entries.

std::error_code increment() override

Sets CurrentEntry to the next entry in the directory on success, to directory_entry() at end,...

RedirectingFSDirIterImpl(const Twine &Path, RedirectingFileSystem::DirectoryEntry::iterator Begin, RedirectingFileSystem::DirectoryEntry::iterator End, std::error_code &EC)

A helper class to hold the common YAML parsing state.

RedirectingFileSystemParser(yaml::Stream &S)

static RedirectingFileSystem::Entry * lookupOrCreateEntry(RedirectingFileSystem *FS, StringRef Name, RedirectingFileSystem::Entry *ParentEntry=nullptr)

bool parse(yaml::Node *Root, RedirectingFileSystem *FS)

decltype(Contents)::iterator iterator

A single file or directory in the VFS.

StringRef getName() const

EntryKind getKind() const

A virtual file system parsed from a YAML file.

@ OverlayDir

The roots are relative to the directory where the Overlay YAML file.

@ CWD

The roots are relative to the current working directory.

bool exists(const Twine &Path) override

Check whether Path exists.

void printImpl(raw_ostream &OS, PrintType Type, unsigned IndentLevel) const override

std::vector< llvm::StringRef > getRoots() const

directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override

Get a directory_iterator for Dir.

ErrorOr< LookupResult > lookupPath(StringRef Path) const

Looks up Path in Roots and returns a LookupResult giving the matched entry and, if the entry was a Fi...

RedirectKind

The type of redirection to perform.

@ Fallthrough

Lookup the redirected path first (ie.

@ Fallback

Lookup the provided path first and if that fails, "fallback" to a lookup of the redirected path.

@ RedirectOnly

Only lookup the redirected path, do not lookup the originally provided path.

void setFallthrough(bool Fallthrough)

Sets the redirection kind to Fallthrough if true or RedirectOnly otherwise.

void visitChildFileSystems(VisitCallbackTy Callback) override

std::error_code getRealPath(const Twine &Path, SmallVectorImpl< char > &Output) override

Gets real path of Path e.g.

ErrorOr< std::unique_ptr< File > > openFileForRead(const Twine &Path) override

Get a File object for the text file at Path, if one exists.

void setOverlayFileDir(StringRef PrefixDir)

llvm::ErrorOr< std::string > getCurrentWorkingDirectory() const override

Get the working directory of this file system.

void setRedirection(RedirectingFileSystem::RedirectKind Kind)

std::error_code isLocal(const Twine &Path, bool &Result) override

Is the file mounted on a local filesystem?

static std::unique_ptr< RedirectingFileSystem > create(std::unique_ptr< MemoryBuffer > Buffer, SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath, void *DiagContext, IntrusiveRefCntPtr< FileSystem > ExternalFS)

Parses Buffer, which is expected to be in YAML format and returns a virtual file system representing ...

std::error_code setCurrentWorkingDirectory(const Twine &Path) override

Set the working directory.

StringRef getOverlayFileDir() const

void printEntry(raw_ostream &OS, Entry *E, unsigned IndentLevel=0) const

The result of a status operation.

llvm::sys::fs::UniqueID getUniqueID() const

bool equivalent(const Status &Other) const

static Status copyWithNewName(const Status &In, const Twine &NewName)

Get a copy of a Status with a different name.

bool isStatusKnown() const

bool ExposesExternalVFSPath

Whether this entity has an external path different from the virtual path, and the external path is ex...

static Status copyWithNewSize(const Status &In, uint64_t NewSize)

Get a copy of a Status with a different size.

llvm::sys::fs::file_type getType() const

bool isRegularFile() const

StringRef getName() const

Returns the name that should be used for this file or directory.

std::size_t NumOpenFileForReadCalls

std::size_t NumIsLocalCalls

std::size_t NumExistsCalls

void printImpl(raw_ostream &OS, PrintType Type, unsigned IndentLevel) const override

std::size_t NumDirBeginCalls

std::size_t NumGetRealPathCalls

std::size_t NumStatusCalls

void addFileMapping(StringRef VirtualPath, StringRef RealPath)

void write(llvm::raw_ostream &OS)

void addDirectoryMapping(StringRef VirtualPath, StringRef RealPath)

InMemoryDirectory(Status Stat)

InMemoryNode * addChild(StringRef Name, std::unique_ptr< InMemoryNode > Child)

Status getStatus(const Twine &RequestedName) const override

Return the Status for this node.

const_iterator end() const

static bool classof(const InMemoryNode *N)

InMemoryNode * getChild(StringRef Name) const

const_iterator begin() const

UniqueID getUniqueID() const

decltype(Entries)::const_iterator const_iterator

std::string toString(unsigned Indent) const override

Status getStatus(const Twine &RequestedName) const override

Return the Status for this node.

std::string toString(unsigned Indent) const override

InMemoryFile(Status Stat, std::unique_ptr< llvm::MemoryBuffer > Buffer)

static bool classof(const InMemoryNode *N)

llvm::MemoryBuffer * getBuffer() const

The in memory file system is a tree of Nodes.

StringRef getFileName() const

Get the filename of this node (the name without the directory part).

InMemoryNodeKind getKind() const

virtual ~InMemoryNode()=default

InMemoryNode(llvm::StringRef FileName, InMemoryNodeKind Kind)

virtual std::string toString(unsigned Indent) const =0

virtual Status getStatus(const Twine &RequestedName) const =0

Return the Status for this node.

A member of a directory, yielded by a directory_iterator.

llvm::StringRef path() const

llvm::sys::fs::file_type type() const

An input iterator over the entries in a virtual path, similar to llvm::sys::fs::directory_iterator.

directory_iterator & increment(std::error_code &EC)

Equivalent to operator++, with an error code.

An input iterator over the recursive contents of a virtual path, similar to llvm::sys::fs::recursive_...

recursive_directory_iterator()=default

Construct an 'end' iterator.

recursive_directory_iterator & increment(std::error_code &EC)

Equivalent to operator++, with an error code.

Abstract base class for all Nodes.

This class represents a YAML stream potentially containing multiple documents.

document_iterator begin()

void printError(Node *N, const Twine &Msg, SourceMgr::DiagKind Kind=SourceMgr::DK_Error)

Iterator abstraction for Documents over a Stream.

This provides a very simple, boring adaptor for a begin and end iterator into a range type.

#define llvm_unreachable(msg)

Marks that the current location is not supposed to be reachable.

@ Resolved

Queried, materialization begun.

void make_absolute(const Twine &current_directory, SmallVectorImpl< char > &path)

Make path an absolute path.

const file_t kInvalidFile

std::error_code real_path(const Twine &path, SmallVectorImpl< char > &output, bool expand_tilde=false)

Collapse all .

std::error_code closeFile(file_t &F)

Close the file object.

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.

std::error_code status(const Twine &path, file_status &result, bool follow=true)

Get file status as if by POSIX stat().

@ OF_Text

The file should be opened in text mode on platforms like z/OS that make this distinction.

file_type

An enumeration for the file system's view of the type.

std::error_code set_current_path(const Twine &path)

Set the current path.

std::error_code is_local(const Twine &path, bool &result)

Is the file mounted on a local filesystem?

Expected< file_t > openNativeFileForRead(const Twine &Name, 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.

std::error_code current_path(SmallVectorImpl< char > &result)

Get the current path.

bool is_directory(const basic_file_status &status)

Does status represent a directory?

StringRef get_separator(Style style=Style::native)

Return the preferred separator for this platform.

StringRef root_path(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)

Get root path.

const_iterator begin(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)

Get begin iterator over path.

reverse_iterator rend(StringRef path LLVM_LIFETIME_BOUND)

Get reverse end iterator over path.

bool remove_dots(SmallVectorImpl< char > &path, bool remove_dot_dot=false, Style style=Style::native)

In-place remove any '.

StringRef parent_path(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)

Get parent path.

StringRef remove_leading_dotslash(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)

Remove redundant leading "./" pieces and consecutive separators.

StringRef filename(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)

Get filename.

bool is_absolute(const Twine &path, Style style=Style::native)

Is path absolute?

void append(SmallVectorImpl< char > &path, const Twine &a, const Twine &b="", const Twine &c="", const Twine &d="")

Append to path.

reverse_iterator rbegin(StringRef path LLVM_LIFETIME_BOUND, Style style=Style::native)

Get reverse begin iterator over path.

const_iterator end(StringRef path LLVM_LIFETIME_BOUND)

Get end iterator over path.

bool is_separator(char value, Style style=Style::native)

Check whether the given char is a path separator on the host OS.

std::chrono::time_point< std::chrono::system_clock, D > TimePoint

A time point on the system clock.

TimePoint< std::chrono::seconds > toTimePoint(std::time_t T)

Convert a std::time_t to a TimePoint.

void collectVFSFromYAML(std::unique_ptr< llvm::MemoryBuffer > Buffer, llvm::SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath, SmallVectorImpl< YAMLVFSEntry > &CollectedEntries, void *DiagContext=nullptr, IntrusiveRefCntPtr< FileSystem > ExternalFS=getRealFileSystem())

Collect all pairs of <virtual path, real path> entries from the YAMLFilePath.

std::unique_ptr< FileSystem > getVFSFromYAML(std::unique_ptr< llvm::MemoryBuffer > Buffer, llvm::SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath, void *DiagContext=nullptr, IntrusiveRefCntPtr< FileSystem > ExternalFS=getRealFileSystem())

Gets a FileSystem for a virtual file system described in YAML format.

std::unique_ptr< FileSystem > createPhysicalFileSystem()

Create an vfs::FileSystem for the 'real' file system, as seen by the operating system.

static sys::fs::UniqueID getFileID(sys::fs::UniqueID Parent, llvm::StringRef Name, llvm::StringRef Contents)

llvm::sys::fs::UniqueID getNextVirtualUniqueID()

Get a globally unique ID for a virtual file or directory.

static sys::fs::UniqueID getUniqueID(hash_code Hash)

IntrusiveRefCntPtr< FileSystem > getRealFileSystem()

Gets an vfs::FileSystem for the 'real' file system, as seen by the operating system.

static sys::fs::UniqueID getDirectoryID(sys::fs::UniqueID Parent, llvm::StringRef Name)

std::string escape(StringRef Input, bool EscapePrintable=true)

Escape Input for a double quoted scalar; if EscapePrintable is true, all UTF8 sequences will be escap...

This is an optimization pass for GlobalISel generic memory operations.

std::error_code make_error_code(BitcodeError E)

iterator_range< T > make_range(T x, T y)

Convenience function for iterating over sub-ranges.

@ no_such_file_or_directory

@ operation_not_permitted

auto reverse(ContainerTy &&C)

decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)

Error write(MCStreamer &Out, ArrayRef< std::string > Inputs, OnCuIndexOverflow OverflowOptValue)

void sort(IteratorTy Start, IteratorTy End)

raw_ostream & dbgs()

dbgs() - This returns a reference to a raw_ostream for debugging messages.

OutputIt move(R &&Range, OutputIt Out)

Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.

const char * toString(DWARFSectionKind Kind)

hash_code hash_combine(const Ts &...args)

Combine values into a single hash_code.

std::error_code errorToErrorCode(Error Err)

Helper for converting an ECError to a std::error_code.

Implement std::hash so that hash_code can be used in STL containers.

Represents the result of a path lookup into the RedirectingFileSystem.

Entry * E

The entry the looked-up path corresponds to.

LookupResult(Entry *E, sys::path::const_iterator Start, sys::path::const_iterator End)

void getPath(llvm::SmallVectorImpl< char > &Path) const

Get the (canonical) path of the found entry.

An interface for virtual file systems to provide an iterator over the (non-recursive) contents of a d...

directory_entry CurrentEntry

Status makeStatus() const

std::unique_ptr< llvm::MemoryBuffer > Buffer