VirtualFileSystem.cpp 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194
  1. //===- VirtualFileSystem.cpp - Virtual File System Layer --------*- C++ -*-===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. // This file implements the VirtualFileSystem interface.
  10. //===----------------------------------------------------------------------===//
  11. #include "clang/Basic/VirtualFileSystem.h"
  12. #include "llvm/ADT/DenseMap.h"
  13. #include "llvm/ADT/STLExtras.h"
  14. #include "llvm/ADT/StringExtras.h"
  15. #include "llvm/ADT/StringSet.h"
  16. #include "llvm/ADT/iterator_range.h"
  17. #include "llvm/Support/Errc.h"
  18. #include "llvm/Support/MemoryBuffer.h"
  19. #include "llvm/Support/Path.h"
  20. #include "llvm/Support/YAMLParser.h"
  21. #include <atomic>
  22. #include <memory>
  23. using namespace clang;
  24. using namespace clang::vfs;
  25. using namespace llvm;
  26. using llvm::sys::fs::file_status;
  27. using llvm::sys::fs::file_type;
  28. using llvm::sys::fs::perms;
  29. using llvm::sys::fs::UniqueID;
  30. Status::Status(const file_status &Status)
  31. : UID(Status.getUniqueID()), MTime(Status.getLastModificationTime()),
  32. User(Status.getUser()), Group(Status.getGroup()), Size(Status.getSize()),
  33. Type(Status.type()), Perms(Status.permissions()), IsVFSMapped(false) {}
  34. Status::Status(StringRef Name, StringRef ExternalName, UniqueID UID,
  35. sys::TimeValue MTime, uint32_t User, uint32_t Group,
  36. uint64_t Size, file_type Type, perms Perms)
  37. : Name(Name), UID(UID), MTime(MTime), User(User), Group(Group), Size(Size),
  38. Type(Type), Perms(Perms), IsVFSMapped(false) {}
  39. bool Status::equivalent(const Status &Other) const {
  40. return getUniqueID() == Other.getUniqueID();
  41. }
  42. bool Status::isDirectory() const {
  43. return Type == file_type::directory_file;
  44. }
  45. bool Status::isRegularFile() const {
  46. return Type == file_type::regular_file;
  47. }
  48. bool Status::isOther() const {
  49. return exists() && !isRegularFile() && !isDirectory() && !isSymlink();
  50. }
  51. bool Status::isSymlink() const {
  52. return Type == file_type::symlink_file;
  53. }
  54. bool Status::isStatusKnown() const {
  55. return Type != file_type::status_error;
  56. }
  57. bool Status::exists() const {
  58. return isStatusKnown() && Type != file_type::file_not_found;
  59. }
  60. File::~File() {}
  61. FileSystem::~FileSystem() {}
  62. ErrorOr<std::unique_ptr<MemoryBuffer>>
  63. FileSystem::getBufferForFile(const llvm::Twine &Name, int64_t FileSize,
  64. bool RequiresNullTerminator, bool IsVolatile) {
  65. auto F = openFileForRead(Name);
  66. if (!F)
  67. return F.getError();
  68. return (*F)->getBuffer(Name, FileSize, RequiresNullTerminator, IsVolatile);
  69. }
  70. //===-----------------------------------------------------------------------===/
  71. // RealFileSystem implementation
  72. //===-----------------------------------------------------------------------===/
  73. namespace {
  74. /// \brief Wrapper around a raw file descriptor.
  75. class RealFile : public File {
  76. int FD;
  77. Status S;
  78. friend class RealFileSystem;
  79. RealFile(int FD) : FD(FD) {
  80. assert(FD >= 0 && "Invalid or inactive file descriptor");
  81. }
  82. public:
  83. ~RealFile() override;
  84. ErrorOr<Status> status() override;
  85. ErrorOr<std::unique_ptr<MemoryBuffer>>
  86. getBuffer(const Twine &Name, int64_t FileSize = -1,
  87. bool RequiresNullTerminator = true,
  88. bool IsVolatile = false) override;
  89. std::error_code close() override;
  90. void setName(StringRef Name) override;
  91. };
  92. } // end anonymous namespace
  93. RealFile::~RealFile() { close(); }
  94. ErrorOr<Status> RealFile::status() {
  95. assert(FD != -1 && "cannot stat closed file");
  96. if (!S.isStatusKnown()) {
  97. file_status RealStatus;
  98. if (std::error_code EC = sys::fs::status(FD, RealStatus))
  99. return EC;
  100. Status NewS(RealStatus);
  101. NewS.setName(S.getName());
  102. S = std::move(NewS);
  103. }
  104. return S;
  105. }
  106. ErrorOr<std::unique_ptr<MemoryBuffer>>
  107. RealFile::getBuffer(const Twine &Name, int64_t FileSize,
  108. bool RequiresNullTerminator, bool IsVolatile) {
  109. assert(FD != -1 && "cannot get buffer for closed file");
  110. return MemoryBuffer::getOpenFile(FD, Name, FileSize, RequiresNullTerminator,
  111. IsVolatile);
  112. }
  113. // FIXME: This is terrible, we need this for ::close.
  114. #if !defined(_MSC_VER) && !defined(__MINGW32__)
  115. #include <unistd.h>
  116. #include <sys/uio.h>
  117. #else
  118. #include <io.h>
  119. #ifndef S_ISFIFO
  120. #define S_ISFIFO(x) (0)
  121. #endif
  122. #endif
  123. #include "llvm/Support/FileSystem.h" // HLSL Change
  124. std::error_code RealFile::close() {
  125. if (llvm::sys::fs::msf_close(FD)) // HLSL Change
  126. return std::error_code(errno, std::generic_category());
  127. FD = -1;
  128. return std::error_code();
  129. }
  130. void RealFile::setName(StringRef Name) {
  131. S.setName(Name);
  132. }
  133. namespace {
  134. /// \brief The file system according to your operating system.
  135. class RealFileSystem : public FileSystem {
  136. public:
  137. ErrorOr<Status> status(const Twine &Path) override;
  138. ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override;
  139. directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
  140. };
  141. } // end anonymous namespace
  142. ErrorOr<Status> RealFileSystem::status(const Twine &Path) {
  143. sys::fs::file_status RealStatus;
  144. if (std::error_code EC = sys::fs::status(Path, RealStatus))
  145. return EC;
  146. Status Result(RealStatus);
  147. Result.setName(Path.str());
  148. return Result;
  149. }
  150. ErrorOr<std::unique_ptr<File>>
  151. RealFileSystem::openFileForRead(const Twine &Name) {
  152. int FD;
  153. if (std::error_code EC = sys::fs::openFileForRead(Name, FD))
  154. return EC;
  155. std::unique_ptr<File> Result(new RealFile(FD));
  156. Result->setName(Name.str());
  157. return std::move(Result);
  158. }
  159. #if 0 // HLSL Change Starts
  160. IntrusiveRefCntPtr<FileSystem> vfs::getRealFileSystem() {
  161. static IntrusiveRefCntPtr<FileSystem> FS = new RealFileSystem();
  162. return FS;
  163. }
  164. #else
  165. static RealFileSystem g_RealFileSystem;
  166. IntrusiveRefCntPtr<FileSystem> vfs::getRealFileSystem() {
  167. g_RealFileSystem.Retain(); // never let go - TODO: guard against refcount wraparound
  168. IntrusiveRefCntPtr<FileSystem> Result(&g_RealFileSystem);
  169. return Result;
  170. }
  171. #endif // HLSL Change Ends
  172. namespace {
  173. class RealFSDirIter : public clang::vfs::detail::DirIterImpl {
  174. std::string Path;
  175. llvm::sys::fs::directory_iterator Iter;
  176. public:
  177. RealFSDirIter(const Twine &_Path, std::error_code &EC)
  178. : Path(_Path.str()), Iter(Path, EC) {
  179. if (!EC && Iter != llvm::sys::fs::directory_iterator()) {
  180. llvm::sys::fs::file_status S;
  181. EC = Iter->status(S);
  182. if (!EC) {
  183. CurrentEntry = Status(S);
  184. CurrentEntry.setName(Iter->path());
  185. }
  186. }
  187. }
  188. std::error_code increment() override {
  189. std::error_code EC;
  190. Iter.increment(EC);
  191. if (EC) {
  192. return EC;
  193. } else if (Iter == llvm::sys::fs::directory_iterator()) {
  194. CurrentEntry = Status();
  195. } else {
  196. llvm::sys::fs::file_status S;
  197. EC = Iter->status(S);
  198. CurrentEntry = Status(S);
  199. CurrentEntry.setName(Iter->path());
  200. }
  201. return EC;
  202. }
  203. };
  204. }
  205. directory_iterator RealFileSystem::dir_begin(const Twine &Dir,
  206. std::error_code &EC) {
  207. return directory_iterator(std::make_shared<RealFSDirIter>(Dir, EC));
  208. }
  209. //===-----------------------------------------------------------------------===/
  210. // OverlayFileSystem implementation
  211. //===-----------------------------------------------------------------------===/
  212. OverlayFileSystem::OverlayFileSystem(IntrusiveRefCntPtr<FileSystem> BaseFS) {
  213. pushOverlay(BaseFS);
  214. }
  215. void OverlayFileSystem::pushOverlay(IntrusiveRefCntPtr<FileSystem> FS) {
  216. FSList.push_back(FS);
  217. }
  218. ErrorOr<Status> OverlayFileSystem::status(const Twine &Path) {
  219. // FIXME: handle symlinks that cross file systems
  220. for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) {
  221. ErrorOr<Status> Status = (*I)->status(Path);
  222. if (Status || Status.getError() != llvm::errc::no_such_file_or_directory)
  223. return Status;
  224. }
  225. return make_error_code(llvm::errc::no_such_file_or_directory);
  226. }
  227. ErrorOr<std::unique_ptr<File>>
  228. OverlayFileSystem::openFileForRead(const llvm::Twine &Path) {
  229. // FIXME: handle symlinks that cross file systems
  230. for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) {
  231. auto Result = (*I)->openFileForRead(Path);
  232. if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
  233. return Result;
  234. }
  235. return make_error_code(llvm::errc::no_such_file_or_directory);
  236. }
  237. clang::vfs::detail::DirIterImpl::~DirIterImpl() { }
  238. namespace {
  239. class OverlayFSDirIterImpl : public clang::vfs::detail::DirIterImpl {
  240. OverlayFileSystem &Overlays;
  241. std::string Path;
  242. OverlayFileSystem::iterator CurrentFS;
  243. directory_iterator CurrentDirIter;
  244. llvm::StringSet<> SeenNames;
  245. std::error_code incrementFS() {
  246. assert(CurrentFS != Overlays.overlays_end() && "incrementing past end");
  247. ++CurrentFS;
  248. for (auto E = Overlays.overlays_end(); CurrentFS != E; ++CurrentFS) {
  249. std::error_code EC;
  250. CurrentDirIter = (*CurrentFS)->dir_begin(Path, EC);
  251. if (EC && EC != errc::no_such_file_or_directory)
  252. return EC;
  253. if (CurrentDirIter != directory_iterator())
  254. break; // found
  255. }
  256. return std::error_code();
  257. }
  258. std::error_code incrementDirIter(bool IsFirstTime) {
  259. assert((IsFirstTime || CurrentDirIter != directory_iterator()) &&
  260. "incrementing past end");
  261. std::error_code EC;
  262. if (!IsFirstTime)
  263. CurrentDirIter.increment(EC);
  264. if (!EC && CurrentDirIter == directory_iterator())
  265. EC = incrementFS();
  266. return EC;
  267. }
  268. std::error_code incrementImpl(bool IsFirstTime) {
  269. while (true) {
  270. std::error_code EC = incrementDirIter(IsFirstTime);
  271. if (EC || CurrentDirIter == directory_iterator()) {
  272. CurrentEntry = Status();
  273. return EC;
  274. }
  275. CurrentEntry = *CurrentDirIter;
  276. StringRef Name = llvm::sys::path::filename(CurrentEntry.getName());
  277. if (SeenNames.insert(Name).second)
  278. return EC; // name not seen before
  279. }
  280. llvm_unreachable("returned above");
  281. }
  282. public:
  283. OverlayFSDirIterImpl(const Twine &Path, OverlayFileSystem &FS,
  284. std::error_code &EC)
  285. : Overlays(FS), Path(Path.str()), CurrentFS(Overlays.overlays_begin()) {
  286. CurrentDirIter = (*CurrentFS)->dir_begin(Path, EC);
  287. EC = incrementImpl(true);
  288. }
  289. std::error_code increment() override { return incrementImpl(false); }
  290. };
  291. } // end anonymous namespace
  292. directory_iterator OverlayFileSystem::dir_begin(const Twine &Dir,
  293. std::error_code &EC) {
  294. return directory_iterator(
  295. std::make_shared<OverlayFSDirIterImpl>(Dir, *this, EC));
  296. }
  297. //===-----------------------------------------------------------------------===/
  298. // VFSFromYAML implementation
  299. //===-----------------------------------------------------------------------===/
  300. namespace {
  301. enum EntryKind {
  302. EK_Directory,
  303. EK_File
  304. };
  305. /// \brief A single file or directory in the VFS.
  306. class Entry {
  307. EntryKind Kind;
  308. std::string Name;
  309. public:
  310. virtual ~Entry();
  311. Entry(EntryKind K, StringRef Name) : Kind(K), Name(Name) {}
  312. StringRef getName() const { return Name; }
  313. EntryKind getKind() const { return Kind; }
  314. };
  315. class DirectoryEntry : public Entry {
  316. std::vector<Entry *> Contents;
  317. Status S;
  318. public:
  319. ~DirectoryEntry() override;
  320. DirectoryEntry(StringRef Name, std::vector<Entry *> Contents, Status S)
  321. : Entry(EK_Directory, Name), Contents(std::move(Contents)),
  322. S(std::move(S)) {}
  323. Status getStatus() { return S; }
  324. typedef std::vector<Entry *>::iterator iterator;
  325. iterator contents_begin() { return Contents.begin(); }
  326. iterator contents_end() { return Contents.end(); }
  327. static bool classof(const Entry *E) { return E->getKind() == EK_Directory; }
  328. };
  329. class FileEntry : public Entry {
  330. public:
  331. enum NameKind {
  332. NK_NotSet,
  333. NK_External,
  334. NK_Virtual
  335. };
  336. private:
  337. std::string ExternalContentsPath;
  338. NameKind UseName;
  339. public:
  340. FileEntry(StringRef Name, StringRef ExternalContentsPath, NameKind UseName)
  341. : Entry(EK_File, Name), ExternalContentsPath(ExternalContentsPath),
  342. UseName(UseName) {}
  343. StringRef getExternalContentsPath() const { return ExternalContentsPath; }
  344. /// \brief whether to use the external path as the name for this file.
  345. bool useExternalName(bool GlobalUseExternalName) const {
  346. return UseName == NK_NotSet ? GlobalUseExternalName
  347. : (UseName == NK_External);
  348. }
  349. static bool classof(const Entry *E) { return E->getKind() == EK_File; }
  350. };
  351. class VFSFromYAML;
  352. class VFSFromYamlDirIterImpl : public clang::vfs::detail::DirIterImpl {
  353. std::string Dir;
  354. VFSFromYAML &FS;
  355. DirectoryEntry::iterator Current, End;
  356. public:
  357. VFSFromYamlDirIterImpl(const Twine &Path, VFSFromYAML &FS,
  358. DirectoryEntry::iterator Begin,
  359. DirectoryEntry::iterator End, std::error_code &EC);
  360. std::error_code increment() override;
  361. };
  362. /// \brief A virtual file system parsed from a YAML file.
  363. ///
  364. /// Currently, this class allows creating virtual directories and mapping
  365. /// virtual file paths to existing external files, available in \c ExternalFS.
  366. ///
  367. /// The basic structure of the parsed file is:
  368. /// \verbatim
  369. /// {
  370. /// 'version': <version number>,
  371. /// <optional configuration>
  372. /// 'roots': [
  373. /// <directory entries>
  374. /// ]
  375. /// }
  376. /// \endverbatim
  377. ///
  378. /// All configuration options are optional.
  379. /// 'case-sensitive': <boolean, default=true>
  380. /// 'use-external-names': <boolean, default=true>
  381. ///
  382. /// Virtual directories are represented as
  383. /// \verbatim
  384. /// {
  385. /// 'type': 'directory',
  386. /// 'name': <string>,
  387. /// 'contents': [ <file or directory entries> ]
  388. /// }
  389. /// \endverbatim
  390. ///
  391. /// The default attributes for virtual directories are:
  392. /// \verbatim
  393. /// MTime = now() when created
  394. /// Perms = 0777
  395. /// User = Group = 0
  396. /// Size = 0
  397. /// UniqueID = unspecified unique value
  398. /// \endverbatim
  399. ///
  400. /// Re-mapped files are represented as
  401. /// \verbatim
  402. /// {
  403. /// 'type': 'file',
  404. /// 'name': <string>,
  405. /// 'use-external-name': <boolean> # Optional
  406. /// 'external-contents': <path to external file>)
  407. /// }
  408. /// \endverbatim
  409. ///
  410. /// and inherit their attributes from the external contents.
  411. ///
  412. /// In both cases, the 'name' field may contain multiple path components (e.g.
  413. /// /path/to/file). However, any directory that contains more than one child
  414. /// must be uniquely represented by a directory entry.
  415. class VFSFromYAML : public vfs::FileSystem {
  416. std::vector<Entry *> Roots; ///< The root(s) of the virtual file system.
  417. /// \brief The file system to use for external references.
  418. IntrusiveRefCntPtr<FileSystem> ExternalFS;
  419. /// @name Configuration
  420. /// @{
  421. /// \brief Whether to perform case-sensitive comparisons.
  422. ///
  423. /// Currently, case-insensitive matching only works correctly with ASCII.
  424. bool CaseSensitive;
  425. /// \brief Whether to use to use the value of 'external-contents' for the
  426. /// names of files. This global value is overridable on a per-file basis.
  427. bool UseExternalNames;
  428. /// @}
  429. friend class VFSFromYAMLParser;
  430. private:
  431. VFSFromYAML(IntrusiveRefCntPtr<FileSystem> ExternalFS)
  432. : ExternalFS(ExternalFS), CaseSensitive(true), UseExternalNames(true) {}
  433. /// \brief Looks up \p Path in \c Roots.
  434. ErrorOr<Entry *> lookupPath(const Twine &Path);
  435. /// \brief Looks up the path <tt>[Start, End)</tt> in \p From, possibly
  436. /// recursing into the contents of \p From if it is a directory.
  437. ErrorOr<Entry *> lookupPath(sys::path::const_iterator Start,
  438. sys::path::const_iterator End, Entry *From);
  439. /// \brief Get the status of a given an \c Entry.
  440. ErrorOr<Status> status(const Twine &Path, Entry *E);
  441. public:
  442. ~VFSFromYAML() override;
  443. /// \brief Parses \p Buffer, which is expected to be in YAML format and
  444. /// returns a virtual file system representing its contents.
  445. static VFSFromYAML *create(std::unique_ptr<MemoryBuffer> Buffer,
  446. SourceMgr::DiagHandlerTy DiagHandler,
  447. void *DiagContext,
  448. IntrusiveRefCntPtr<FileSystem> ExternalFS);
  449. ErrorOr<Status> status(const Twine &Path) override;
  450. ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override;
  451. directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override{
  452. ErrorOr<Entry *> E = lookupPath(Dir);
  453. if (!E) {
  454. EC = E.getError();
  455. return directory_iterator();
  456. }
  457. ErrorOr<Status> S = status(Dir, *E);
  458. if (!S) {
  459. EC = S.getError();
  460. return directory_iterator();
  461. }
  462. if (!S->isDirectory()) {
  463. EC = std::error_code(static_cast<int>(errc::not_a_directory),
  464. std::system_category());
  465. return directory_iterator();
  466. }
  467. DirectoryEntry *D = cast<DirectoryEntry>(*E);
  468. return directory_iterator(std::make_shared<VFSFromYamlDirIterImpl>(Dir,
  469. *this, D->contents_begin(), D->contents_end(), EC));
  470. }
  471. };
  472. /// \brief A helper class to hold the common YAML parsing state.
  473. class VFSFromYAMLParser {
  474. yaml::Stream &Stream;
  475. void error(yaml::Node *N, const Twine &Msg) {
  476. Stream.printError(N, Msg);
  477. }
  478. // false on error
  479. bool parseScalarString(yaml::Node *N, StringRef &Result,
  480. SmallVectorImpl<char> &Storage) {
  481. yaml::ScalarNode *S = dyn_cast<yaml::ScalarNode>(N);
  482. if (!S) {
  483. error(N, "expected string");
  484. return false;
  485. }
  486. Result = S->getValue(Storage);
  487. return true;
  488. }
  489. // false on error
  490. bool parseScalarBool(yaml::Node *N, bool &Result) {
  491. SmallString<5> Storage;
  492. StringRef Value;
  493. if (!parseScalarString(N, Value, Storage))
  494. return false;
  495. if (Value.equals_lower("true") || Value.equals_lower("on") ||
  496. Value.equals_lower("yes") || Value == "1") {
  497. Result = true;
  498. return true;
  499. } else if (Value.equals_lower("false") || Value.equals_lower("off") ||
  500. Value.equals_lower("no") || Value == "0") {
  501. Result = false;
  502. return true;
  503. }
  504. error(N, "expected boolean value");
  505. return false;
  506. }
  507. struct KeyStatus {
  508. KeyStatus(bool Required=false) : Required(Required), Seen(false) {}
  509. bool Required;
  510. bool Seen;
  511. };
  512. typedef std::pair<StringRef, KeyStatus> KeyStatusPair;
  513. // false on error
  514. bool checkDuplicateOrUnknownKey(yaml::Node *KeyNode, StringRef Key,
  515. DenseMap<StringRef, KeyStatus> &Keys) {
  516. if (!Keys.count(Key)) {
  517. error(KeyNode, "unknown key");
  518. return false;
  519. }
  520. KeyStatus &S = Keys[Key];
  521. if (S.Seen) {
  522. error(KeyNode, Twine("duplicate key '") + Key + "'");
  523. return false;
  524. }
  525. S.Seen = true;
  526. return true;
  527. }
  528. // false on error
  529. bool checkMissingKeys(yaml::Node *Obj, DenseMap<StringRef, KeyStatus> &Keys) {
  530. for (DenseMap<StringRef, KeyStatus>::iterator I = Keys.begin(),
  531. E = Keys.end();
  532. I != E; ++I) {
  533. if (I->second.Required && !I->second.Seen) {
  534. error(Obj, Twine("missing key '") + I->first + "'");
  535. return false;
  536. }
  537. }
  538. return true;
  539. }
  540. Entry *parseEntry(yaml::Node *N) {
  541. yaml::MappingNode *M = dyn_cast<yaml::MappingNode>(N);
  542. if (!M) {
  543. error(N, "expected mapping node for file or directory entry");
  544. return nullptr;
  545. }
  546. KeyStatusPair Fields[] = {
  547. KeyStatusPair("name", true),
  548. KeyStatusPair("type", true),
  549. KeyStatusPair("contents", false),
  550. KeyStatusPair("external-contents", false),
  551. KeyStatusPair("use-external-name", false),
  552. };
  553. DenseMap<StringRef, KeyStatus> Keys(
  554. &Fields[0], Fields + sizeof(Fields)/sizeof(Fields[0]));
  555. bool HasContents = false; // external or otherwise
  556. std::vector<Entry *> EntryArrayContents;
  557. std::string ExternalContentsPath;
  558. std::string Name;
  559. FileEntry::NameKind UseExternalName = FileEntry::NK_NotSet;
  560. EntryKind Kind;
  561. for (yaml::MappingNode::iterator I = M->begin(), E = M->end(); I != E;
  562. ++I) {
  563. StringRef Key;
  564. // Reuse the buffer for key and value, since we don't look at key after
  565. // parsing value.
  566. SmallString<256> Buffer;
  567. if (!parseScalarString(I->getKey(), Key, Buffer))
  568. return nullptr;
  569. if (!checkDuplicateOrUnknownKey(I->getKey(), Key, Keys))
  570. return nullptr;
  571. StringRef Value;
  572. if (Key == "name") {
  573. if (!parseScalarString(I->getValue(), Value, Buffer))
  574. return nullptr;
  575. Name = Value;
  576. } else if (Key == "type") {
  577. if (!parseScalarString(I->getValue(), Value, Buffer))
  578. return nullptr;
  579. if (Value == "file")
  580. Kind = EK_File;
  581. else if (Value == "directory")
  582. Kind = EK_Directory;
  583. else {
  584. error(I->getValue(), "unknown value for 'type'");
  585. return nullptr;
  586. }
  587. } else if (Key == "contents") {
  588. if (HasContents) {
  589. error(I->getKey(),
  590. "entry already has 'contents' or 'external-contents'");
  591. return nullptr;
  592. }
  593. HasContents = true;
  594. yaml::SequenceNode *Contents =
  595. dyn_cast<yaml::SequenceNode>(I->getValue());
  596. if (!Contents) {
  597. // FIXME: this is only for directories, what about files?
  598. error(I->getValue(), "expected array");
  599. return nullptr;
  600. }
  601. for (yaml::SequenceNode::iterator I = Contents->begin(),
  602. E = Contents->end();
  603. I != E; ++I) {
  604. if (Entry *E = parseEntry(&*I))
  605. EntryArrayContents.push_back(E);
  606. else
  607. return nullptr;
  608. }
  609. } else if (Key == "external-contents") {
  610. if (HasContents) {
  611. error(I->getKey(),
  612. "entry already has 'contents' or 'external-contents'");
  613. return nullptr;
  614. }
  615. HasContents = true;
  616. if (!parseScalarString(I->getValue(), Value, Buffer))
  617. return nullptr;
  618. ExternalContentsPath = Value;
  619. } else if (Key == "use-external-name") {
  620. bool Val;
  621. if (!parseScalarBool(I->getValue(), Val))
  622. return nullptr;
  623. UseExternalName = Val ? FileEntry::NK_External : FileEntry::NK_Virtual;
  624. } else {
  625. llvm_unreachable("key missing from Keys");
  626. }
  627. }
  628. if (Stream.failed())
  629. return nullptr;
  630. // check for missing keys
  631. if (!HasContents) {
  632. error(N, "missing key 'contents' or 'external-contents'");
  633. return nullptr;
  634. }
  635. if (!checkMissingKeys(N, Keys))
  636. return nullptr;
  637. // check invalid configuration
  638. if (Kind == EK_Directory && UseExternalName != FileEntry::NK_NotSet) {
  639. error(N, "'use-external-name' is not supported for directories");
  640. return nullptr;
  641. }
  642. // Remove trailing slash(es), being careful not to remove the root path
  643. StringRef Trimmed(Name);
  644. size_t RootPathLen = sys::path::root_path(Trimmed).size();
  645. while (Trimmed.size() > RootPathLen &&
  646. sys::path::is_separator(Trimmed.back()))
  647. Trimmed = Trimmed.slice(0, Trimmed.size()-1);
  648. // Get the last component
  649. StringRef LastComponent = sys::path::filename(Trimmed);
  650. Entry *Result = nullptr;
  651. switch (Kind) {
  652. case EK_File:
  653. Result = new FileEntry(LastComponent, std::move(ExternalContentsPath),
  654. UseExternalName);
  655. break;
  656. case EK_Directory:
  657. Result = new DirectoryEntry(LastComponent, std::move(EntryArrayContents),
  658. Status("", "", getNextVirtualUniqueID(), sys::TimeValue::now(), 0, 0,
  659. 0, file_type::directory_file, sys::fs::all_all));
  660. break;
  661. }
  662. StringRef Parent = sys::path::parent_path(Trimmed);
  663. if (Parent.empty())
  664. return Result;
  665. // if 'name' contains multiple components, create implicit directory entries
  666. for (sys::path::reverse_iterator I = sys::path::rbegin(Parent),
  667. E = sys::path::rend(Parent);
  668. I != E; ++I) {
  669. Result = new DirectoryEntry(*I, llvm::makeArrayRef(Result),
  670. Status("", "", getNextVirtualUniqueID(), sys::TimeValue::now(), 0, 0,
  671. 0, file_type::directory_file, sys::fs::all_all));
  672. }
  673. return Result;
  674. }
  675. public:
  676. VFSFromYAMLParser(yaml::Stream &S) : Stream(S) {}
  677. // false on error
  678. bool parse(yaml::Node *Root, VFSFromYAML *FS) {
  679. yaml::MappingNode *Top = dyn_cast<yaml::MappingNode>(Root);
  680. if (!Top) {
  681. error(Root, "expected mapping node");
  682. return false;
  683. }
  684. KeyStatusPair Fields[] = {
  685. KeyStatusPair("version", true),
  686. KeyStatusPair("case-sensitive", false),
  687. KeyStatusPair("use-external-names", false),
  688. KeyStatusPair("roots", true),
  689. };
  690. DenseMap<StringRef, KeyStatus> Keys(
  691. &Fields[0], Fields + sizeof(Fields)/sizeof(Fields[0]));
  692. // Parse configuration and 'roots'
  693. for (yaml::MappingNode::iterator I = Top->begin(), E = Top->end(); I != E;
  694. ++I) {
  695. SmallString<10> KeyBuffer;
  696. StringRef Key;
  697. if (!parseScalarString(I->getKey(), Key, KeyBuffer))
  698. return false;
  699. if (!checkDuplicateOrUnknownKey(I->getKey(), Key, Keys))
  700. return false;
  701. if (Key == "roots") {
  702. yaml::SequenceNode *Roots = dyn_cast<yaml::SequenceNode>(I->getValue());
  703. if (!Roots) {
  704. error(I->getValue(), "expected array");
  705. return false;
  706. }
  707. for (yaml::SequenceNode::iterator I = Roots->begin(), E = Roots->end();
  708. I != E; ++I) {
  709. if (Entry *E = parseEntry(&*I))
  710. FS->Roots.push_back(E);
  711. else
  712. return false;
  713. }
  714. } else if (Key == "version") {
  715. StringRef VersionString;
  716. SmallString<4> Storage;
  717. if (!parseScalarString(I->getValue(), VersionString, Storage))
  718. return false;
  719. int Version;
  720. if (VersionString.getAsInteger<int>(10, Version)) {
  721. error(I->getValue(), "expected integer");
  722. return false;
  723. }
  724. if (Version < 0) {
  725. error(I->getValue(), "invalid version number");
  726. return false;
  727. }
  728. if (Version != 0) {
  729. error(I->getValue(), "version mismatch, expected 0");
  730. return false;
  731. }
  732. } else if (Key == "case-sensitive") {
  733. if (!parseScalarBool(I->getValue(), FS->CaseSensitive))
  734. return false;
  735. } else if (Key == "use-external-names") {
  736. if (!parseScalarBool(I->getValue(), FS->UseExternalNames))
  737. return false;
  738. } else {
  739. llvm_unreachable("key missing from Keys");
  740. }
  741. }
  742. if (Stream.failed())
  743. return false;
  744. if (!checkMissingKeys(Top, Keys))
  745. return false;
  746. return true;
  747. }
  748. };
  749. } // end of anonymous namespace
  750. Entry::~Entry() {}
  751. DirectoryEntry::~DirectoryEntry() { llvm::DeleteContainerPointers(Contents); }
  752. VFSFromYAML::~VFSFromYAML() { llvm::DeleteContainerPointers(Roots); }
  753. VFSFromYAML *VFSFromYAML::create(std::unique_ptr<MemoryBuffer> Buffer,
  754. SourceMgr::DiagHandlerTy DiagHandler,
  755. void *DiagContext,
  756. IntrusiveRefCntPtr<FileSystem> ExternalFS) {
  757. SourceMgr SM;
  758. yaml::Stream Stream(Buffer->getMemBufferRef(), SM);
  759. SM.setDiagHandler(DiagHandler, DiagContext);
  760. yaml::document_iterator DI = Stream.begin();
  761. yaml::Node *Root = DI->getRoot();
  762. if (DI == Stream.end() || !Root) {
  763. SM.PrintMessage(SMLoc(), SourceMgr::DK_Error, "expected root node");
  764. return nullptr;
  765. }
  766. VFSFromYAMLParser P(Stream);
  767. std::unique_ptr<VFSFromYAML> FS(new VFSFromYAML(ExternalFS));
  768. if (!P.parse(Root, FS.get()))
  769. return nullptr;
  770. return FS.release();
  771. }
  772. ErrorOr<Entry *> VFSFromYAML::lookupPath(const Twine &Path_) {
  773. SmallString<256> Path;
  774. Path_.toVector(Path);
  775. // Handle relative paths
  776. if (std::error_code EC = sys::fs::make_absolute(Path))
  777. return EC;
  778. if (Path.empty())
  779. return make_error_code(llvm::errc::invalid_argument);
  780. sys::path::const_iterator Start = sys::path::begin(Path);
  781. sys::path::const_iterator End = sys::path::end(Path);
  782. for (std::vector<Entry *>::iterator I = Roots.begin(), E = Roots.end();
  783. I != E; ++I) {
  784. ErrorOr<Entry *> Result = lookupPath(Start, End, *I);
  785. if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
  786. return Result;
  787. }
  788. return make_error_code(llvm::errc::no_such_file_or_directory);
  789. }
  790. ErrorOr<Entry *> VFSFromYAML::lookupPath(sys::path::const_iterator Start,
  791. sys::path::const_iterator End,
  792. Entry *From) {
  793. if (Start->equals("."))
  794. ++Start;
  795. // FIXME: handle ..
  796. if (CaseSensitive ? !Start->equals(From->getName())
  797. : !Start->equals_lower(From->getName()))
  798. // failure to match
  799. return make_error_code(llvm::errc::no_such_file_or_directory);
  800. ++Start;
  801. if (Start == End) {
  802. // Match!
  803. return From;
  804. }
  805. DirectoryEntry *DE = dyn_cast<DirectoryEntry>(From);
  806. if (!DE)
  807. return make_error_code(llvm::errc::not_a_directory);
  808. for (DirectoryEntry::iterator I = DE->contents_begin(),
  809. E = DE->contents_end();
  810. I != E; ++I) {
  811. ErrorOr<Entry *> Result = lookupPath(Start, End, *I);
  812. if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
  813. return Result;
  814. }
  815. return make_error_code(llvm::errc::no_such_file_or_directory);
  816. }
  817. ErrorOr<Status> VFSFromYAML::status(const Twine &Path, Entry *E) {
  818. assert(E != nullptr);
  819. std::string PathStr(Path.str());
  820. if (FileEntry *F = dyn_cast<FileEntry>(E)) {
  821. ErrorOr<Status> S = ExternalFS->status(F->getExternalContentsPath());
  822. assert(!S || S->getName() == F->getExternalContentsPath());
  823. if (S && !F->useExternalName(UseExternalNames))
  824. S->setName(PathStr);
  825. if (S)
  826. S->IsVFSMapped = true;
  827. return S;
  828. } else { // directory
  829. DirectoryEntry *DE = cast<DirectoryEntry>(E);
  830. Status S = DE->getStatus();
  831. S.setName(PathStr);
  832. return S;
  833. }
  834. }
  835. ErrorOr<Status> VFSFromYAML::status(const Twine &Path) {
  836. ErrorOr<Entry *> Result = lookupPath(Path);
  837. if (!Result)
  838. return Result.getError();
  839. return status(Path, *Result);
  840. }
  841. ErrorOr<std::unique_ptr<File>> VFSFromYAML::openFileForRead(const Twine &Path) {
  842. ErrorOr<Entry *> E = lookupPath(Path);
  843. if (!E)
  844. return E.getError();
  845. FileEntry *F = dyn_cast<FileEntry>(*E);
  846. if (!F) // FIXME: errc::not_a_file?
  847. return make_error_code(llvm::errc::invalid_argument);
  848. auto Result = ExternalFS->openFileForRead(F->getExternalContentsPath());
  849. if (!Result)
  850. return Result;
  851. if (!F->useExternalName(UseExternalNames))
  852. (*Result)->setName(Path.str());
  853. return Result;
  854. }
  855. IntrusiveRefCntPtr<FileSystem>
  856. vfs::getVFSFromYAML(std::unique_ptr<MemoryBuffer> Buffer,
  857. SourceMgr::DiagHandlerTy DiagHandler, void *DiagContext,
  858. IntrusiveRefCntPtr<FileSystem> ExternalFS) {
  859. return VFSFromYAML::create(std::move(Buffer), DiagHandler, DiagContext,
  860. ExternalFS);
  861. }
  862. UniqueID vfs::getNextVirtualUniqueID() {
  863. static std::atomic<unsigned> UID;
  864. unsigned ID = ++UID;
  865. // The following assumes that uint64_t max will never collide with a real
  866. // dev_t value from the OS.
  867. return UniqueID(std::numeric_limits<uint64_t>::max(), ID);
  868. }
  869. #ifndef NDEBUG
  870. static bool pathHasTraversal(StringRef Path) {
  871. using namespace llvm::sys;
  872. for (StringRef Comp : llvm::make_range(path::begin(Path), path::end(Path)))
  873. if (Comp == "." || Comp == "..")
  874. return true;
  875. return false;
  876. }
  877. #endif
  878. void YAMLVFSWriter::addFileMapping(StringRef VirtualPath, StringRef RealPath) {
  879. assert(sys::path::is_absolute(VirtualPath) && "virtual path not absolute");
  880. assert(sys::path::is_absolute(RealPath) && "real path not absolute");
  881. assert(!pathHasTraversal(VirtualPath) && "path traversal is not supported");
  882. Mappings.emplace_back(VirtualPath, RealPath);
  883. }
  884. namespace {
  885. class JSONWriter {
  886. llvm::raw_ostream &OS;
  887. SmallVector<StringRef, 16> DirStack;
  888. inline unsigned getDirIndent() { return 4 * DirStack.size(); }
  889. inline unsigned getFileIndent() { return 4 * (DirStack.size() + 1); }
  890. bool containedIn(StringRef Parent, StringRef Path);
  891. StringRef containedPart(StringRef Parent, StringRef Path);
  892. void startDirectory(StringRef Path);
  893. void endDirectory();
  894. void writeEntry(StringRef VPath, StringRef RPath);
  895. public:
  896. JSONWriter(llvm::raw_ostream &OS) : OS(OS) {}
  897. void write(ArrayRef<YAMLVFSEntry> Entries, Optional<bool> IsCaseSensitive);
  898. };
  899. }
  900. bool JSONWriter::containedIn(StringRef Parent, StringRef Path) {
  901. using namespace llvm::sys;
  902. // Compare each path component.
  903. auto IParent = path::begin(Parent), EParent = path::end(Parent);
  904. for (auto IChild = path::begin(Path), EChild = path::end(Path);
  905. IParent != EParent && IChild != EChild; ++IParent, ++IChild) {
  906. if (*IParent != *IChild)
  907. return false;
  908. }
  909. // Have we exhausted the parent path?
  910. return IParent == EParent;
  911. }
  912. StringRef JSONWriter::containedPart(StringRef Parent, StringRef Path) {
  913. assert(!Parent.empty());
  914. assert(containedIn(Parent, Path));
  915. return Path.slice(Parent.size() + 1, StringRef::npos);
  916. }
  917. void JSONWriter::startDirectory(StringRef Path) {
  918. StringRef Name =
  919. DirStack.empty() ? Path : containedPart(DirStack.back(), Path);
  920. DirStack.push_back(Path);
  921. unsigned Indent = getDirIndent();
  922. OS.indent(Indent) << "{\n";
  923. OS.indent(Indent + 2) << "'type': 'directory',\n";
  924. OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(Name) << "\",\n";
  925. OS.indent(Indent + 2) << "'contents': [\n";
  926. }
  927. void JSONWriter::endDirectory() {
  928. unsigned Indent = getDirIndent();
  929. OS.indent(Indent + 2) << "]\n";
  930. OS.indent(Indent) << "}";
  931. DirStack.pop_back();
  932. }
  933. void JSONWriter::writeEntry(StringRef VPath, StringRef RPath) {
  934. unsigned Indent = getFileIndent();
  935. OS.indent(Indent) << "{\n";
  936. OS.indent(Indent + 2) << "'type': 'file',\n";
  937. OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(VPath) << "\",\n";
  938. OS.indent(Indent + 2) << "'external-contents': \""
  939. << llvm::yaml::escape(RPath) << "\"\n";
  940. OS.indent(Indent) << "}";
  941. }
  942. void JSONWriter::write(ArrayRef<YAMLVFSEntry> Entries,
  943. Optional<bool> IsCaseSensitive) {
  944. using namespace llvm::sys;
  945. OS << "{\n"
  946. " 'version': 0,\n";
  947. if (IsCaseSensitive.hasValue())
  948. OS << " 'case-sensitive': '"
  949. << (IsCaseSensitive.getValue() ? "true" : "false") << "',\n";
  950. OS << " 'roots': [\n";
  951. if (!Entries.empty()) {
  952. const YAMLVFSEntry &Entry = Entries.front();
  953. startDirectory(path::parent_path(Entry.VPath));
  954. writeEntry(path::filename(Entry.VPath), Entry.RPath);
  955. for (const auto &Entry : Entries.slice(1)) {
  956. StringRef Dir = path::parent_path(Entry.VPath);
  957. if (Dir == DirStack.back())
  958. OS << ",\n";
  959. else {
  960. while (!DirStack.empty() && !containedIn(DirStack.back(), Dir)) {
  961. OS << "\n";
  962. endDirectory();
  963. }
  964. OS << ",\n";
  965. startDirectory(Dir);
  966. }
  967. writeEntry(path::filename(Entry.VPath), Entry.RPath);
  968. }
  969. while (!DirStack.empty()) {
  970. OS << "\n";
  971. endDirectory();
  972. }
  973. OS << "\n";
  974. }
  975. OS << " ]\n"
  976. << "}\n";
  977. }
  978. void YAMLVFSWriter::write(llvm::raw_ostream &OS) {
  979. std::sort(Mappings.begin(), Mappings.end(),
  980. [](const YAMLVFSEntry &LHS, const YAMLVFSEntry &RHS) {
  981. return LHS.VPath < RHS.VPath;
  982. });
  983. JSONWriter(OS).write(Mappings, IsCaseSensitive);
  984. }
  985. VFSFromYamlDirIterImpl::VFSFromYamlDirIterImpl(const Twine &_Path,
  986. VFSFromYAML &FS,
  987. DirectoryEntry::iterator Begin,
  988. DirectoryEntry::iterator End,
  989. std::error_code &EC)
  990. : Dir(_Path.str()), FS(FS), Current(Begin), End(End) {
  991. if (Current != End) {
  992. SmallString<128> PathStr(Dir);
  993. llvm::sys::path::append(PathStr, (*Current)->getName());
  994. llvm::ErrorOr<vfs::Status> S = FS.status(PathStr);
  995. if (S)
  996. CurrentEntry = *S;
  997. else
  998. EC = S.getError();
  999. }
  1000. }
  1001. std::error_code VFSFromYamlDirIterImpl::increment() {
  1002. assert(Current != End && "cannot iterate past end");
  1003. if (++Current != End) {
  1004. SmallString<128> PathStr(Dir);
  1005. llvm::sys::path::append(PathStr, (*Current)->getName());
  1006. llvm::ErrorOr<vfs::Status> S = FS.status(PathStr);
  1007. if (!S)
  1008. return S.getError();
  1009. CurrentEntry = *S;
  1010. } else {
  1011. CurrentEntry = Status();
  1012. }
  1013. return std::error_code();
  1014. }
  1015. vfs::recursive_directory_iterator::recursive_directory_iterator(FileSystem &FS_,
  1016. const Twine &Path,
  1017. std::error_code &EC)
  1018. : FS(&FS_) {
  1019. directory_iterator I = FS->dir_begin(Path, EC);
  1020. if (!EC && I != directory_iterator()) {
  1021. State = std::make_shared<IterState>();
  1022. State->push(I);
  1023. }
  1024. }
  1025. vfs::recursive_directory_iterator &
  1026. recursive_directory_iterator::increment(std::error_code &EC) {
  1027. assert(FS && State && !State->empty() && "incrementing past end");
  1028. assert(State->top()->isStatusKnown() && "non-canonical end iterator");
  1029. vfs::directory_iterator End;
  1030. if (State->top()->isDirectory()) {
  1031. vfs::directory_iterator I = FS->dir_begin(State->top()->getName(), EC);
  1032. if (EC)
  1033. return *this;
  1034. if (I != End) {
  1035. State->push(I);
  1036. return *this;
  1037. }
  1038. }
  1039. while (!State->empty() && State->top().increment(EC) == End)
  1040. State->pop();
  1041. if (State->empty())
  1042. State.reset(); // end iterator
  1043. return *this;
  1044. }