VirtualFileSystem.cpp 37 KB

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