llvm.org GIT mirror llvm / 5681311
[VFS] Move RedirectingFileSystem interface into header (NFC) This moves the RedirectingFileSystem into the header so it can be extended. This is needed in LLDB we need a way to obtain the external path to deal with FILE* and file descriptor APIs. Discussion on the mailing list: http://lists.llvm.org/pipermail/llvm-dev/2018-November/127755.html Differential revision: https://reviews.llvm.org/D54277 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@351265 91177308-0d34-0410-b5e6-96231b3b80d8 Jonas Devlieghere 1 year, 10 months ago
2 changed file(s) with 406 addition(s) and 354 deletion(s). Raw diff Collapse all Expand all
2323 #include "llvm/Support/Chrono.h"
2424 #include "llvm/Support/ErrorOr.h"
2525 #include "llvm/Support/FileSystem.h"
26 #include "llvm/Support/Path.h"
2627 #include "llvm/Support/SourceMgr.h"
2728 #include
2829 #include
494495 std::string RPath;
495496 };
496497
498 class VFSFromYamlDirIterImpl;
499 class RedirectingFileSystemParser;
500
501 /// A virtual file system parsed from a YAML file.
502 ///
503 /// Currently, this class allows creating virtual directories and mapping
504 /// virtual file paths to existing external files, available in \c ExternalFS.
505 ///
506 /// The basic structure of the parsed file is:
507 /// \verbatim
508 /// {
509 /// 'version': ,
510 ///
511 /// 'roots': [
512 ///
513 /// ]
514 /// }
515 /// \endverbatim
516 ///
517 /// All configuration options are optional.
518 /// 'case-sensitive':
519 /// 'use-external-names':
520 /// 'overlay-relative':
521 /// 'fallthrough':
522 ///
523 /// Virtual directories are represented as
524 /// \verbatim
525 /// {
526 /// 'type': 'directory',
527 /// 'name': ,
528 /// 'contents': [ ]
529 /// }
530 /// \endverbatim
531 ///
532 /// The default attributes for virtual directories are:
533 /// \verbatim
534 /// MTime = now() when created
535 /// Perms = 0777
536 /// User = Group = 0
537 /// Size = 0
538 /// UniqueID = unspecified unique value
539 /// \endverbatim
540 ///
541 /// Re-mapped files are represented as
542 /// \verbatim
543 /// {
544 /// 'type': 'file',
545 /// 'name': ,
546 /// 'use-external-name': # Optional
547 /// 'external-contents':
548 /// }
549 /// \endverbatim
550 ///
551 /// and inherit their attributes from the external contents.
552 ///
553 /// In both cases, the 'name' field may contain multiple path components (e.g.
554 /// /path/to/file). However, any directory that contains more than one child
555 /// must be uniquely represented by a directory entry.
556 class RedirectingFileSystem : public vfs::FileSystem {
557 public:
558 enum EntryKind { EK_Directory, EK_File };
559
560 /// A single file or directory in the VFS.
561 class Entry {
562 EntryKind Kind;
563 std::string Name;
564
565 public:
566 Entry(EntryKind K, StringRef Name) : Kind(K), Name(Name) {}
567 virtual ~Entry() = default;
568
569 StringRef getName() const { return Name; }
570 EntryKind getKind() const { return Kind; }
571 };
572
573 class RedirectingDirectoryEntry : public Entry {
574 std::vector> Contents;
575 Status S;
576
577 public:
578 RedirectingDirectoryEntry(StringRef Name,
579 std::vector> Contents,
580 Status S)
581 : Entry(EK_Directory, Name), Contents(std::move(Contents)),
582 S(std::move(S)) {}
583 RedirectingDirectoryEntry(StringRef Name, Status S)
584 : Entry(EK_Directory, Name), S(std::move(S)) {}
585
586 Status getStatus() { return S; }
587
588 void addContent(std::unique_ptr Content) {
589 Contents.push_back(std::move(Content));
590 }
591
592 Entry *getLastContent() const { return Contents.back().get(); }
593
594 using iterator = decltype(Contents)::iterator;
595
596 iterator contents_begin() { return Contents.begin(); }
597 iterator contents_end() { return Contents.end(); }
598
599 static bool classof(const Entry *E) { return E->getKind() == EK_Directory; }
600 };
601
602 class RedirectingFileEntry : public Entry {
603 public:
604 enum NameKind { NK_NotSet, NK_External, NK_Virtual };
605
606 private:
607 std::string ExternalContentsPath;
608 NameKind UseName;
609
610 public:
611 RedirectingFileEntry(StringRef Name, StringRef ExternalContentsPath,
612 NameKind UseName)
613 : Entry(EK_File, Name), ExternalContentsPath(ExternalContentsPath),
614 UseName(UseName) {}
615
616 StringRef getExternalContentsPath() const { return ExternalContentsPath; }
617
618 /// whether to use the external path as the name for this file.
619 bool useExternalName(bool GlobalUseExternalName) const {
620 return UseName == NK_NotSet ? GlobalUseExternalName
621 : (UseName == NK_External);
622 }
623
624 NameKind getUseName() const { return UseName; }
625
626 static bool classof(const Entry *E) { return E->getKind() == EK_File; }
627 };
628
629 private:
630 friend class VFSFromYamlDirIterImpl;
631 friend class RedirectingFileSystemParser;
632
633 /// The root(s) of the virtual file system.
634 std::vector> Roots;
635
636 /// The file system to use for external references.
637 IntrusiveRefCntPtr ExternalFS;
638
639 /// If IsRelativeOverlay is set, this represents the directory
640 /// path that should be prefixed to each 'external-contents' entry
641 /// when reading from YAML files.
642 std::string ExternalContentsPrefixDir;
643
644 /// @name Configuration
645 /// @{
646
647 /// Whether to perform case-sensitive comparisons.
648 ///
649 /// Currently, case-insensitive matching only works correctly with ASCII.
650 bool CaseSensitive = true;
651
652 /// IsRelativeOverlay marks whether a ExternalContentsPrefixDir path must
653 /// be prefixed in every 'external-contents' when reading from YAML files.
654 bool IsRelativeOverlay = false;
655
656 /// Whether to use to use the value of 'external-contents' for the
657 /// names of files. This global value is overridable on a per-file basis.
658 bool UseExternalNames = true;
659
660 /// Whether to attempt a file lookup in external file system after it wasn't
661 /// found in VFS.
662 bool IsFallthrough = true;
663 /// @}
664
665 /// Virtual file paths and external files could be canonicalized without "..",
666 /// "." and "./" in their paths. FIXME: some unittests currently fail on
667 /// win32 when using remove_dots and remove_leading_dotslash on paths.
668 bool UseCanonicalizedPaths =
669 #ifdef _WIN32
670 false;
671 #else
672 true;
673 #endif
674
675 RedirectingFileSystem(IntrusiveRefCntPtr ExternalFS)
676 : ExternalFS(std::move(ExternalFS)) {}
677
678 /// Looks up the path [Start, End) in \p From, possibly
679 /// recursing into the contents of \p From if it is a directory.
680 ErrorOr lookupPath(llvm::sys::path::const_iterator Start,
681 llvm::sys::path::const_iterator End,
682 Entry *From) const;
683
684 /// Get the status of a given an \c Entry.
685 ErrorOr status(const Twine &Path, Entry *E);
686
687 public:
688 /// Looks up \p Path in \c Roots.
689 ErrorOr lookupPath(const Twine &Path) const;
690
691 /// Parses \p Buffer, which is expected to be in YAML format and
692 /// returns a virtual file system representing its contents.
693 static RedirectingFileSystem *
694 create(std::unique_ptr Buffer,
695 SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath,
696 void *DiagContext, IntrusiveRefCntPtr ExternalFS);
697
698 ErrorOr status(const Twine &Path) override;
699 ErrorOr> openFileForRead(const Twine &Path) override;
700
701 std::error_code getRealPath(const Twine &Path,
702 SmallVectorImpl &Output) const override;
703
704 llvm::ErrorOr getCurrentWorkingDirectory() const override;
705
706 std::error_code setCurrentWorkingDirectory(const Twine &Path) override;
707
708 std::error_code isLocal(const Twine &Path, bool &Result) override;
709
710 directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
711
712 void setExternalContentsPrefixDir(StringRef PrefixDir);
713
714 StringRef getExternalContentsPrefixDir() const;
715
716 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
717 LLVM_DUMP_METHOD void dump() const;
718 LLVM_DUMP_METHOD void dumpEntry(Entry *E, int NumSpaces = 0) const;
719 #endif
720 };
721
497722 /// Collect all pairs of entries from the
498723 /// \p YAMLFilePath. This is used by the module dependency collector to forward
499724 /// the entries into the reproducer output VFS YAML file.
942942 // RedirectingFileSystem implementation
943943 //===-----------------------------------------------------------------------===/
944944
945 namespace {
946
947 enum EntryKind { EK_Directory, EK_File };
948
949 /// A single file or directory in the VFS.
950 class Entry {
951 EntryKind Kind;
952 std::string Name;
953
954 public:
955 Entry(EntryKind K, StringRef Name) : Kind(K), Name(Name) {}
956 virtual ~Entry() = default;
957
958 StringRef getName() const { return Name; }
959 EntryKind getKind() const { return Kind; }
960 };
961
962 class RedirectingDirectoryEntry : public Entry {
963 std::vector> Contents;
964 Status S;
965
966 public:
967 RedirectingDirectoryEntry(StringRef Name,
968 std::vector> Contents,
969 Status S)
970 : Entry(EK_Directory, Name), Contents(std::move(Contents)),
971 S(std::move(S)) {}
972 RedirectingDirectoryEntry(StringRef Name, Status S)
973 : Entry(EK_Directory, Name), S(std::move(S)) {}
974
975 Status getStatus() { return S; }
976
977 void addContent(std::unique_ptr Content) {
978 Contents.push_back(std::move(Content));
979 }
980
981 Entry *getLastContent() const { return Contents.back().get(); }
982
983 using iterator = decltype(Contents)::iterator;
984
985 iterator contents_begin() { return Contents.begin(); }
986 iterator contents_end() { return Contents.end(); }
987
988 static bool classof(const Entry *E) { return E->getKind() == EK_Directory; }
989 };
990
991 class RedirectingFileEntry : public Entry {
992 public:
993 enum NameKind { NK_NotSet, NK_External, NK_Virtual };
994
995 private:
996 std::string ExternalContentsPath;
997 NameKind UseName;
998
999 public:
1000 RedirectingFileEntry(StringRef Name, StringRef ExternalContentsPath,
1001 NameKind UseName)
1002 : Entry(EK_File, Name), ExternalContentsPath(ExternalContentsPath),
1003 UseName(UseName) {}
1004
1005 StringRef getExternalContentsPath() const { return ExternalContentsPath; }
1006
1007 /// whether to use the external path as the name for this file.
1008 bool useExternalName(bool GlobalUseExternalName) const {
1009 return UseName == NK_NotSet ? GlobalUseExternalName
1010 : (UseName == NK_External);
1011 }
1012
1013 NameKind getUseName() const { return UseName; }
1014
1015 static bool classof(const Entry *E) { return E->getKind() == EK_File; }
1016 };
1017
1018945 // FIXME: reuse implementation common with OverlayFSDirIterImpl as these
1019946 // iterators are conceptually similar.
1020 class VFSFromYamlDirIterImpl : public llvm::vfs::detail::DirIterImpl {
947 class llvm::vfs::VFSFromYamlDirIterImpl
948 : public llvm::vfs::detail::DirIterImpl {
1021949 std::string Dir;
1022 RedirectingDirectoryEntry::iterator Current, End;
950 RedirectingFileSystem::RedirectingDirectoryEntry::iterator Current, End;
1023951
1024952 // To handle 'fallthrough' mode we need to iterate at first through
1025953 // RedirectingDirectoryEntry and then through ExternalFS. These operations are
1049977 /// @}
1050978
1051979 public:
1052 VFSFromYamlDirIterImpl(const Twine &Path,
1053 RedirectingDirectoryEntry::iterator Begin,
1054 RedirectingDirectoryEntry::iterator End,
1055 bool IterateExternalFS, FileSystem &ExternalFS,
1056 std::error_code &EC);
980 VFSFromYamlDirIterImpl(
981 const Twine &Path,
982 RedirectingFileSystem::RedirectingDirectoryEntry::iterator Begin,
983 RedirectingFileSystem::RedirectingDirectoryEntry::iterator End,
984 bool IterateExternalFS, FileSystem &ExternalFS, std::error_code &EC);
1057985
1058986 std::error_code increment() override;
1059987 };
1060988
1061 /// A virtual file system parsed from a YAML file.
1062 ///
1063 /// Currently, this class allows creating virtual directories and mapping
1064 /// virtual file paths to existing external files, available in \c ExternalFS.
1065 ///
1066 /// The basic structure of the parsed file is:
1067 /// \verbatim
1068 /// {
1069 /// 'version': ,
1070 ///
1071 /// 'roots': [
1072 ///
1073 /// ]
1074 /// }
1075 /// \endverbatim
1076 ///
1077 /// All configuration options are optional.
1078 /// 'case-sensitive':
1079 /// 'use-external-names':
1080 /// 'overlay-relative':
1081 /// 'fallthrough':
1082 ///
1083 /// Virtual directories are represented as
1084 /// \verbatim
1085 /// {
1086 /// 'type': 'directory',
1087 /// 'name': ,
1088 /// 'contents': [ ]
1089 /// }
1090 /// \endverbatim
1091 ///
1092 /// The default attributes for virtual directories are:
1093 /// \verbatim
1094 /// MTime = now() when created
1095 /// Perms = 0777
1096 /// User = Group = 0
1097 /// Size = 0
1098 /// UniqueID = unspecified unique value
1099 /// \endverbatim
1100 ///
1101 /// Re-mapped files are represented as
1102 /// \verbatim
1103 /// {
1104 /// 'type': 'file',
1105 /// 'name': ,
1106 /// 'use-external-name': # Optional
1107 /// 'external-contents':
1108 /// }
1109 /// \endverbatim
1110 ///
1111 /// and inherit their attributes from the external contents.
1112 ///
1113 /// In both cases, the 'name' field may contain multiple path components (e.g.
1114 /// /path/to/file). However, any directory that contains more than one child
1115 /// must be uniquely represented by a directory entry.
1116 class RedirectingFileSystem : public vfs::FileSystem {
1117 friend class RedirectingFileSystemParser;
1118
1119 /// The root(s) of the virtual file system.
1120 std::vector> Roots;
1121
1122 /// The file system to use for external references.
1123 IntrusiveRefCntPtr ExternalFS;
1124
1125 /// If IsRelativeOverlay is set, this represents the directory
1126 /// path that should be prefixed to each 'external-contents' entry
1127 /// when reading from YAML files.
1128 std::string ExternalContentsPrefixDir;
1129
1130 /// @name Configuration
1131 /// @{
1132
1133 /// Whether to perform case-sensitive comparisons.
1134 ///
1135 /// Currently, case-insensitive matching only works correctly with ASCII.
1136 bool CaseSensitive = true;
1137
1138 /// IsRelativeOverlay marks whether a ExternalContentsPrefixDir path must
1139 /// be prefixed in every 'external-contents' when reading from YAML files.
1140 bool IsRelativeOverlay = false;
1141
1142 /// Whether to use to use the value of 'external-contents' for the
1143 /// names of files. This global value is overridable on a per-file basis.
1144 bool UseExternalNames = true;
1145
1146 /// Whether to attempt a file lookup in external file system after it wasn't
1147 /// found in VFS.
1148 bool IsFallthrough = true;
1149 /// @}
1150
1151 /// Virtual file paths and external files could be canonicalized without "..",
1152 /// "." and "./" in their paths. FIXME: some unittests currently fail on
1153 /// win32 when using remove_dots and remove_leading_dotslash on paths.
1154 bool UseCanonicalizedPaths =
1155 #ifdef _WIN32
1156 false;
1157 #else
1158 true;
989 llvm::ErrorOr
990 RedirectingFileSystem::getCurrentWorkingDirectory() const {
991 return ExternalFS->getCurrentWorkingDirectory();
992 }
993
994 std::error_code
995 RedirectingFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
996 return ExternalFS->setCurrentWorkingDirectory(Path);
997 }
998
999 std::error_code RedirectingFileSystem::isLocal(const Twine &Path,
1000 bool &Result) {
1001 return ExternalFS->isLocal(Path, Result);
1002 }
1003
1004 directory_iterator RedirectingFileSystem::dir_begin(const Twine &Dir,
1005 std::error_code &EC) {
1006 ErrorOr E = lookupPath(Dir);
1007 if (!E) {
1008 EC = E.getError();
1009 if (IsFallthrough && EC == errc::no_such_file_or_directory)
1010 return ExternalFS->dir_begin(Dir, EC);
1011 return {};
1012 }
1013 ErrorOr S = status(Dir, *E);
1014 if (!S) {
1015 EC = S.getError();
1016 return {};
1017 }
1018 if (!S->isDirectory()) {
1019 EC = std::error_code(static_cast(errc::not_a_directory),
1020 std::system_category());
1021 return {};
1022 }
1023
1024 auto *D = cast(*E);
1025 return directory_iterator(std::make_shared(
1026 Dir, D->contents_begin(), D->contents_end(),
1027 /*IterateExternalFS=*/IsFallthrough, *ExternalFS, EC));
1028 }
1029
1030 void RedirectingFileSystem::setExternalContentsPrefixDir(StringRef PrefixDir) {
1031 ExternalContentsPrefixDir = PrefixDir.str();
1032 }
1033
1034 StringRef RedirectingFileSystem::getExternalContentsPrefixDir() const {
1035 return ExternalContentsPrefixDir;
1036 }
1037
1038 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1039 LLVM_DUMP_METHOD void RedirectingFileSystem::dump() const {
1040 for (const auto &Root : Roots)
1041 dumpEntry(Root.get());
1042 }
1043
1044 LLVM_DUMP_METHOD void
1045 RedirectingFileSystem::dumpEntry(RedirectingFileSystem::Entry *E,
1046 int NumSpaces) const {
1047 StringRef Name = E->getName();
1048 for (int i = 0, e = NumSpaces; i < e; ++i)
1049 dbgs() << " ";
1050 dbgs() << "'" << Name.str().c_str() << "'"
1051 << "\n";
1052
1053 if (E->getKind() == RedirectingFileSystem::EK_Directory) {
1054 auto *DE = dyn_cast(E);
1055 assert(DE && "Should be a directory");
1056
1057 for (std::unique_ptr &SubEntry :
1058 llvm::make_range(DE->contents_begin(), DE->contents_end()))
1059 dumpEntry(SubEntry.get(), NumSpaces + 2);
1060 }
1061 }
11591062 #endif
11601063
1161 private:
1162 RedirectingFileSystem(IntrusiveRefCntPtr ExternalFS)
1163 : ExternalFS(std::move(ExternalFS)) {}
1164
1165 /// Looks up the path [Start, End) in \p From, possibly
1166 /// recursing into the contents of \p From if it is a directory.
1167 ErrorOr lookupPath(sys::path::const_iterator Start,
1168 sys::path::const_iterator End, Entry *From) const;
1169
1170 /// Get the status of a given an \c Entry.
1171 ErrorOr status(const Twine &Path, Entry *E);
1172
1173 public:
1174 /// Looks up \p Path in \c Roots.
1175 ErrorOr lookupPath(const Twine &Path) const;
1176
1177 /// Parses \p Buffer, which is expected to be in YAML format and
1178 /// returns a virtual file system representing its contents.
1179 static RedirectingFileSystem *
1180 create(std::unique_ptr Buffer,
1181 SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath,
1182 void *DiagContext, IntrusiveRefCntPtr ExternalFS);
1183
1184 ErrorOr status(const Twine &Path) override;
1185 ErrorOr> openFileForRead(const Twine &Path) override;
1186
1187 std::error_code getRealPath(const Twine &Path,
1188 SmallVectorImpl &Output) const override;
1189
1190 llvm::ErrorOr getCurrentWorkingDirectory() const override {
1191 return ExternalFS->getCurrentWorkingDirectory();
1192 }
1193
1194 std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
1195 return ExternalFS->setCurrentWorkingDirectory(Path);
1196 }
1197
1198 std::error_code isLocal(const Twine &Path, bool &Result) override {
1199 return ExternalFS->isLocal(Path, Result);
1200 }
1201
1202 directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override {
1203 ErrorOr E = lookupPath(Dir);
1204 if (!E) {
1205 EC = E.getError();
1206 if (IsFallthrough && EC == errc::no_such_file_or_directory)
1207 return ExternalFS->dir_begin(Dir, EC);
1208 return {};
1209 }
1210 ErrorOr S = status(Dir, *E);
1211 if (!S) {
1212 EC = S.getError();
1213 return {};
1214 }
1215 if (!S->isDirectory()) {
1216 EC = std::error_code(static_cast(errc::not_a_directory),
1217 std::system_category());
1218 return {};
1219 }
1220
1221 auto *D = cast(*E);
1222 return directory_iterator(std::make_shared(
1223 Dir, D->contents_begin(), D->contents_end(),
1224 /*IterateExternalFS=*/IsFallthrough, *ExternalFS, EC));
1225 }
1226
1227 void setExternalContentsPrefixDir(StringRef PrefixDir) {
1228 ExternalContentsPrefixDir = PrefixDir.str();
1229 }
1230
1231 StringRef getExternalContentsPrefixDir() const {
1232 return ExternalContentsPrefixDir;
1233 }
1234
1235 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
1236 LLVM_DUMP_METHOD void dump() const {
1237 for (const auto &Root : Roots)
1238 dumpEntry(Root.get());
1239 }
1240
1241 LLVM_DUMP_METHOD void dumpEntry(Entry *E, int NumSpaces = 0) const {
1242 StringRef Name = E->getName();
1243 for (int i = 0, e = NumSpaces; i < e; ++i)
1244 dbgs() << " ";
1245 dbgs() << "'" << Name.str().c_str() << "'"
1246 << "\n";
1247
1248 if (E->getKind() == EK_Directory) {
1249 auto *DE = dyn_cast(E);
1250 assert(DE && "Should be a directory");
1251
1252 for (std::unique_ptr &SubEntry :
1253 llvm::make_range(DE->contents_begin(), DE->contents_end()))
1254 dumpEntry(SubEntry.get(), NumSpaces + 2);
1255 }
1256 }
1257 #endif
1258 };
1259
12601064 /// A helper class to hold the common YAML parsing state.
1261 class RedirectingFileSystemParser {
1065 class llvm::vfs::RedirectingFileSystemParser {
12621066 yaml::Stream &Stream;
12631067
12641068 void error(yaml::Node *N, const Twine &Msg) { Stream.printError(N, Msg); }
13331137 return true;
13341138 }
13351139
1336 Entry *lookupOrCreateEntry(RedirectingFileSystem *FS, StringRef Name,
1337 Entry *ParentEntry = nullptr) {
1140 RedirectingFileSystem::Entry *
1141 lookupOrCreateEntry(RedirectingFileSystem *FS, StringRef Name,
1142 RedirectingFileSystem::Entry *ParentEntry = nullptr) {
13381143 if (!ParentEntry) { // Look for a existent root
13391144 for (const auto &Root : FS->Roots) {
13401145 if (Name.equals(Root->getName())) {
13431148 }
13441149 }
13451150 } else { // Advance to the next component
1346 auto *DE = dyn_cast(ParentEntry);
1347 for (std::unique_ptr &Content :
1151 auto *DE = dyn_cast(
1152 ParentEntry);
1153 for (std::unique_ptr &Content :
13481154 llvm::make_range(DE->contents_begin(), DE->contents_end())) {
1349 auto *DirContent = dyn_cast(Content.get());
1155 auto *DirContent =
1156 dyn_cast(
1157 Content.get());
13501158 if (DirContent && Name.equals(Content->getName()))
13511159 return DirContent;
13521160 }
13531161 }
13541162
13551163 // ... or create a new one
1356 std::unique_ptr E = llvm::make_unique(
1357 Name,
1358 Status("", getNextVirtualUniqueID(), std::chrono::system_clock::now(),
1359 0, 0, 0, file_type::directory_file, sys::fs::all_all));
1164 std::unique_ptr E =
1165 llvm::make_unique(
1166 Name, Status("", getNextVirtualUniqueID(),
1167 std::chrono::system_clock::now(), 0, 0, 0,
1168 file_type::directory_file, sys::fs::all_all));
13601169
13611170 if (!ParentEntry) { // Add a new root to the overlay
13621171 FS->Roots.push_back(std::move(E));
13641173 return ParentEntry;
13651174 }
13661175
1367 auto *DE = dyn_cast(ParentEntry);
1176 auto *DE =
1177 dyn_cast(ParentEntry);
13681178 DE->addContent(std::move(E));
13691179 return DE->getLastContent();
13701180 }
13711181
1372 void uniqueOverlayTree(RedirectingFileSystem *FS, Entry *SrcE,
1373 Entry *NewParentE = nullptr) {
1182 void uniqueOverlayTree(RedirectingFileSystem *FS,
1183 RedirectingFileSystem::Entry *SrcE,
1184 RedirectingFileSystem::Entry *NewParentE = nullptr) {
13741185 StringRef Name = SrcE->getName();
13751186 switch (SrcE->getKind()) {
1376 case EK_Directory: {
1377 auto *DE = dyn_cast(SrcE);
1187 case RedirectingFileSystem::EK_Directory: {
1188 auto *DE =
1189 dyn_cast(SrcE);
13781190 assert(DE && "Must be a directory");
13791191 // Empty directories could be present in the YAML as a way to
13801192 // describe a file for a current directory after some of its subdir
13811193 // is parsed. This only leads to redundant walks, ignore it.
13821194 if (!Name.empty())
13831195 NewParentE = lookupOrCreateEntry(FS, Name, NewParentE);
1384 for (std::unique_ptr<Entry> &SubEntry :
1196 for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
13851197 llvm::make_range(DE->contents_begin(), DE->contents_end()))
13861198 uniqueOverlayTree(FS, SubEntry.get(), NewParentE);
13871199 break;
13881200 }
1389 case EK_File: {
1390 auto *FE = dyn_cast(SrcE);
1201 case RedirectingFileSystem::EK_File: {
1202 auto *FE = dyn_cast(SrcE);
13911203 assert(FE && "Must be a file");
13921204 assert(NewParentE && "Parent entry must exist");
1393 auto *DE = dyn_cast(NewParentE);
1394 DE->addContent(llvm::make_unique(
1395 Name, FE->getExternalContentsPath(), FE->getUseName()));
1205 auto *DE = dyn_cast(
1206 NewParentE);
1207 DE->addContent(
1208 llvm::make_unique(
1209 Name, FE->getExternalContentsPath(), FE->getUseName()));
13961210 break;
13971211 }
13981212 }
13991213 }
14001214
1401 std::unique_ptr parseEntry(yaml::Node *N, RedirectingFileSystem *FS,
1402 bool IsRootEntry) {
1215 std::unique_ptr
1216 parseEntry(yaml::Node *N, RedirectingFileSystem *FS, bool IsRootEntry) {
14031217 auto *M = dyn_cast(N);
14041218 if (!M) {
14051219 error(N, "expected mapping node for file or directory entry");
14171231 DenseMap Keys(std::begin(Fields), std::end(Fields));
14181232
14191233 bool HasContents = false; // external or otherwise
1420 std::vectorEntry>> EntryArrayContents;
1234 std::vectorRedirectingFileSystem::Entry>>
1235 EntryArrayContents;
14211236 std::string ExternalContentsPath;
14221237 std::string Name;
14231238 yaml::Node *NameValueNode;
1424 auto UseExternalName = RedirectingFileEntry::NK_NotSet;
1425 EntryKind Kind;
1239 auto UseExternalName =
1240 RedirectingFileSystem::RedirectingFileEntry::NK_NotSet;
1241 RedirectingFileSystem::EntryKind Kind;
14261242
14271243 for (auto &I : *M) {
14281244 StringRef Key;
14551271 if (!parseScalarString(I.getValue(), Value, Buffer))
14561272 return nullptr;
14571273 if (Value == "file")
1458 Kind = EK_File;
1274 Kind = RedirectingFileSystem::EK_File;
14591275 else if (Value == "directory")
1460 Kind = EK_Directory;
1276 Kind = RedirectingFileSystem::EK_Directory;
14611277 else {
14621278 error(I.getValue(), "unknown value for 'type'");
14631279 return nullptr;
14771293 }
14781294
14791295 for (auto &I : *Contents) {
1480 if (std::unique_ptr<Entry> E =
1296 if (std::unique_ptr<RedirectingFileSystem::Entry> E =
14811297 parseEntry(&I, FS, /*IsRootEntry*/ false))
14821298 EntryArrayContents.push_back(std::move(E));
14831299 else
15141330 bool Val;
15151331 if (!parseScalarBool(I.getValue(), Val))
15161332 return nullptr;
1517 UseExternalName = Val ? RedirectingFileEntry::NK_External
1518 : RedirectingFileEntry::NK_Virtual;
1333 UseExternalName =
1334 Val ? RedirectingFileSystem::RedirectingFileEntry::NK_External
1335 : RedirectingFileSystem::RedirectingFileEntry::NK_Virtual;
15191336 } else {
15201337 llvm_unreachable("key missing from Keys");
15211338 }
15331350 return nullptr;
15341351
15351352 // check invalid configuration
1536 if (Kind == EK_Directory &&
1537 UseExternalName != RedirectingFileEntry::NK_NotSet) {
1353 if (Kind == RedirectingFileSystem::EK_Directory &&
1354 UseExternalName !=
1355 RedirectingFileSystem::RedirectingFileEntry::NK_NotSet) {
15381356 error(N, "'use-external-name' is not supported for directories");
15391357 return nullptr;
15401358 }
15551373 // Get the last component
15561374 StringRef LastComponent = sys::path::filename(Trimmed);
15571375
1558 std::unique_ptr<Entry> Result;
1376 std::unique_ptr<RedirectingFileSystem::Entry> Result;
15591377 switch (Kind) {
1560 case EK_File:
1561 Result = llvm::make_unique(
1378 case RedirectingFileSystem::EK_File:
1379 Result = llvm::make_unique(
15621380 LastComponent, std::move(ExternalContentsPath), UseExternalName);
15631381 break;
1564 case EK_Directory:
1565 Result = llvm::make_unique(
1566 LastComponent, std::move(EntryArrayContents),
1567 Status("", getNextVirtualUniqueID(), std::chrono::system_clock::now(),
1568 0, 0, 0, file_type::directory_file, sys::fs::all_all));
1382 case RedirectingFileSystem::EK_Directory:
1383 Result =
1384 llvm::make_unique(
1385 LastComponent, std::move(EntryArrayContents),
1386 Status("", getNextVirtualUniqueID(),
1387 std::chrono::system_clock::now(), 0, 0, 0,
1388 file_type::directory_file, sys::fs::all_all));
15691389 break;
15701390 }
15711391
15771397 for (sys::path::reverse_iterator I = sys::path::rbegin(Parent),
15781398 E = sys::path::rend(Parent);
15791399 I != E; ++I) {
1580 std::vectorEntry>> Entries;
1400 std::vectorRedirectingFileSystem::Entry>> Entries;
15811401 Entries.push_back(std::move(Result));
1582 Result = llvm::make_unique(
1583 *I, std::move(Entries),
1584 Status("", getNextVirtualUniqueID(), std::chrono::system_clock::now(),
1585 0, 0, 0, file_type::directory_file, sys::fs::all_all));
1402 Result =
1403 llvm::make_unique(
1404 *I, std::move(Entries),
1405 Status("", getNextVirtualUniqueID(),
1406 std::chrono::system_clock::now(), 0, 0, 0,
1407 file_type::directory_file, sys::fs::all_all));
15861408 }
15871409 return Result;
15881410 }
16081430 };
16091431
16101432 DenseMap Keys(std::begin(Fields), std::end(Fields));
1611 std::vectorEntry>> RootEntries;
1433 std::vectorRedirectingFileSystem::Entry>> RootEntries;
16121434
16131435 // Parse configuration and 'roots'
16141436 for (auto &I : *Top) {
16281450 }
16291451
16301452 for (auto &I : *Roots) {
1631 if (std::unique_ptr<Entry> E =
1453 if (std::unique_ptr<RedirectingFileSystem::Entry> E =
16321454 parseEntry(&I, FS, /*IsRootEntry*/ true))
16331455 RootEntries.push_back(std::move(E));
16341456 else
16851507 }
16861508 };
16871509
1688 } // namespace
1689
16901510 RedirectingFileSystem *
16911511 RedirectingFileSystem::create(std::unique_ptr Buffer,
16921512 SourceMgr::DiagHandlerTy DiagHandler,
17301550 return FS.release();
17311551 }
17321552
1733 ErrorOr<Entry *> RedirectingFileSystem::lookupPath(const Twine &Path_) const {
1553 ErrorOr<RedirectingFileSystem::Entry *>
1554 RedirectingFileSystem::lookupPath(const Twine &Path_) const {
17341555 SmallString<256> Path;
17351556 Path_.toVector(Path);
17361557
17521573 sys::path::const_iterator Start = sys::path::begin(Path);
17531574 sys::path::const_iterator End = sys::path::end(Path);
17541575 for (const auto &Root : Roots) {
1755 ErrorOr<Entry *> Result = lookupPath(Start, End, Root.get());
1576 ErrorOr<RedirectingFileSystem::Entry *> Result =
1577 lookupPath(Start, End, Root.get());
17561578 if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
17571579 return Result;
17581580 }
17591581 return make_error_code(llvm::errc::no_such_file_or_directory);
17601582 }
17611583
1762 ErrorOr<Entry *>
1584 ErrorOr<RedirectingFileSystem::Entry *>
17631585 RedirectingFileSystem::lookupPath(sys::path::const_iterator Start,
17641586 sys::path::const_iterator End,
1765 Entry *From) const {
1587 RedirectingFileSystem::Entry *From) const {
17661588 #ifndef _WIN32
17671589 assert(!isTraversalComponent(*Start) &&
17681590 !isTraversalComponent(From->getName()) &&
17911613 }
17921614 }
17931615
1794 auto *DE = dyn_castDirectoryEntry>(From);
1616 auto *DE = dyn_castFileSystem::RedirectingDirectoryEntry>(From);
17951617 if (!DE)
17961618 return make_error_code(llvm::errc::not_a_directory);
17971619
1798 for (const std::unique_ptr<Entry> &DirEntry :
1620 for (const std::unique_ptr<RedirectingFileSystem::Entry> &DirEntry :
17991621 llvm::make_range(DE->contents_begin(), DE->contents_end())) {
1800 ErrorOr<Entry *> Result = lookupPath(Start, End, DirEntry.get());
1622 ErrorOr<RedirectingFileSystem::Entry *> Result =
1623 lookupPath(Start, End, DirEntry.get());
18011624 if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
18021625 return Result;
18031626 }
18131636 return S;
18141637 }
18151638
1816 ErrorOr RedirectingFileSystem::status(const Twine &Path, Entry *E) {
1639 ErrorOr RedirectingFileSystem::status(const Twine &Path,
1640 RedirectingFileSystem::Entry *E) {
18171641 assert(E != nullptr);
1818 if (auto *F = dyn_castEntry>(E)) {
1642 if (auto *F = dyn_castSystem::RedirectingFileEntry>(E)) {
18191643 ErrorOr S = ExternalFS->status(F->getExternalContentsPath());
18201644 assert(!S || S->getName() == F->getExternalContentsPath());
18211645 if (S)
18231647 *S);
18241648 return S;
18251649 } else { // directory
1826 auto *DE = castDirectoryEntry>(E);
1650 auto *DE = castFileSystem::RedirectingDirectoryEntry>(E);
18271651 return Status::copyWithNewName(DE->getStatus(), Path.str());
18281652 }
18291653 }
18301654
18311655 ErrorOr RedirectingFileSystem::status(const Twine &Path) {
1832 ErrorOr<Entry *> Result = lookupPath(Path);
1656 ErrorOr<RedirectingFileSystem::Entry *> Result = lookupPath(Path);
18331657 if (!Result) {
18341658 if (IsFallthrough &&
18351659 Result.getError() == llvm::errc::no_such_file_or_directory) {
18671691
18681692 ErrorOr>
18691693 RedirectingFileSystem::openFileForRead(const Twine &Path) {
1870 ErrorOr<Entry *> E = lookupPath(Path);
1694 ErrorOr<RedirectingFileSystem::Entry *> E = lookupPath(Path);
18711695 if (!E) {
18721696 if (IsFallthrough &&
18731697 E.getError() == llvm::errc::no_such_file_or_directory) {
18761700 return E.getError();
18771701 }
18781702
1879 auto *F = dyn_castEntry>(*E);
1703 auto *F = dyn_castSystem::RedirectingFileEntry>(*E);
18801704 if (!F) // FIXME: errc::not_a_file?
18811705 return make_error_code(llvm::errc::invalid_argument);
18821706
18981722 std::error_code
18991723 RedirectingFileSystem::getRealPath(const Twine &Path,
19001724 SmallVectorImpl &Output) const {
1901 ErrorOr<Entry *> Result = lookupPath(Path);
1725 ErrorOr<RedirectingFileSystem::Entry *> Result = lookupPath(Path);
19021726 if (!Result) {
19031727 if (IsFallthrough &&
19041728 Result.getError() == llvm::errc::no_such_file_or_directory) {
19071731 return Result.getError();
19081732 }
19091733
1910 if (auto *F = dyn_cast(*Result)) {
1734 if (auto *F =
1735 dyn_cast(*Result)) {
19111736 return ExternalFS->getRealPath(F->getExternalContentsPath(), Output);
19121737 }
19131738 // Even if there is a directory entry, fall back to ExternalFS if allowed,
19261751 std::move(ExternalFS));
19271752 }
19281753
1929 static void getVFSEntries(Entry *SrcE, SmallVectorImpl &Path,
1754 static void getVFSEntries(RedirectingFileSystem::Entry *SrcE,
1755 SmallVectorImpl &Path,
19301756 SmallVectorImpl &Entries) {
19311757 auto Kind = SrcE->getKind();
1932 if (Kind == EK_Directory) {
1933 auto *DE = dyn_cast(SrcE);
1758 if (Kind == RedirectingFileSystem::EK_Directory) {
1759 auto *DE = dyn_cast(SrcE);
19341760 assert(DE && "Must be a directory");
1935 for (std::unique_ptr<Entry> &SubEntry :
1761 for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
19361762 llvm::make_range(DE->contents_begin(), DE->contents_end())) {
19371763 Path.push_back(SubEntry->getName());
19381764 getVFSEntries(SubEntry.get(), Path, Entries);
19411767 return;
19421768 }
19431769
1944 assert(Kind == EK_File && "Must be a EK_File");
1945 auto *FE = dyn_cast(SrcE);
1770 assert(Kind == RedirectingFileSystem::EK_File && "Must be a EK_File");
1771 auto *FE = dyn_cast(SrcE);
19461772 assert(FE && "Must be a file");
19471773 SmallString<128> VPath;
19481774 for (auto &Comp : Path)
19591785 RedirectingFileSystem *VFS = RedirectingFileSystem::create(
19601786 std::move(Buffer), DiagHandler, YAMLFilePath, DiagContext,
19611787 std::move(ExternalFS));
1962 ErrorOr<Entry *> RootE = VFS->lookupPath("/");
1788 ErrorOr<RedirectingFileSystem::Entry *> RootE = VFS->lookupPath("/");
19631789 if (!RootE)
19641790 return;
19651791 SmallVector Components;
21351961 }
21361962
21371963 VFSFromYamlDirIterImpl::VFSFromYamlDirIterImpl(
2138 const Twine &_Path, RedirectingDirectoryEntry::iterator Begin,
2139 RedirectingDirectoryEntry::iterator End, bool IterateExternalFS,
2140 FileSystem &ExternalFS, std::error_code &EC)
1964 const Twine &_Path,
1965 RedirectingFileSystem::RedirectingDirectoryEntry::iterator Begin,
1966 RedirectingFileSystem::RedirectingDirectoryEntry::iterator End,
1967 bool IterateExternalFS, FileSystem &ExternalFS, std::error_code &EC)
21411968 : Dir(_Path.str()), Current(Begin), End(End),
21421969 IterateExternalFS(IterateExternalFS), ExternalFS(ExternalFS) {
21431970 EC = incrementImpl(/*IsFirstTime=*/true);
21772004 llvm::sys::path::append(PathStr, (*Current)->getName());
21782005 sys::fs::file_type Type;
21792006 switch ((*Current)->getKind()) {
2180 case EK_Directory:
2007 case RedirectingFileSystem::EK_Directory:
21812008 Type = sys::fs::file_type::directory_file;
21822009 break;
2183 case EK_File:
2010 case RedirectingFileSystem::EK_File:
21842011 Type = sys::fs::file_type::regular_file;
21852012 break;
21862013 }