VirtualFileSystem.cpp 31 KB

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