VirtualFileSystem.cpp 69 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070
  1. //===- VirtualFileSystem.cpp - Virtual File System Layer ------------------===//
  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. //
  10. // This file implements the VirtualFileSystem interface.
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #include "llvm/Support/VirtualFileSystem.h"
  14. #include "llvm/ADT/ArrayRef.h"
  15. #include "llvm/ADT/DenseMap.h"
  16. #include "llvm/ADT/IntrusiveRefCntPtr.h"
  17. #include "llvm/ADT/None.h"
  18. #include "llvm/ADT/Optional.h"
  19. #include "llvm/ADT/STLExtras.h"
  20. #include "llvm/ADT/SmallString.h"
  21. #include "llvm/ADT/SmallVector.h"
  22. #include "llvm/ADT/StringRef.h"
  23. #include "llvm/ADT/StringSet.h"
  24. #include "llvm/ADT/Twine.h"
  25. #include "llvm/ADT/iterator_range.h"
  26. #include "llvm/Config/llvm-config.h"
  27. #include "llvm/Support/Casting.h"
  28. #include "llvm/Support/Chrono.h"
  29. #include "llvm/Support/Compiler.h"
  30. #include "llvm/Support/Debug.h"
  31. #include "llvm/Support/Errc.h"
  32. #include "llvm/Support/ErrorHandling.h"
  33. #include "llvm/Support/ErrorOr.h"
  34. #include "llvm/Support/FileSystem.h"
  35. #include "llvm/Support/MemoryBuffer.h"
  36. #include "llvm/Support/Path.h"
  37. #include "llvm/Support/Process.h"
  38. #include "llvm/Support/SMLoc.h"
  39. #include "llvm/Support/SourceMgr.h"
  40. #include "llvm/Support/YAMLParser.h"
  41. #include "llvm/Support/raw_ostream.h"
  42. #include <algorithm>
  43. #include <atomic>
  44. #include <cassert>
  45. #include <cstdint>
  46. #include <iterator>
  47. #include <limits>
  48. #include <map>
  49. #include <memory>
  50. #include <mutex>
  51. #include <string>
  52. #include <system_error>
  53. #include <utility>
  54. #include <vector>
  55. using namespace llvm;
  56. using namespace llvm::vfs;
  57. using llvm::sys::fs::file_status;
  58. using llvm::sys::fs::file_type;
  59. using llvm::sys::fs::perms;
  60. using llvm::sys::fs::UniqueID;
  61. Status::Status(const file_status &Status)
  62. : UID(Status.getUniqueID()), MTime(Status.getLastModificationTime()),
  63. User(Status.getUser()), Group(Status.getGroup()), Size(Status.getSize()),
  64. Type(Status.type()), Perms(Status.permissions()) {}
  65. Status::Status(StringRef Name, UniqueID UID, sys::TimePoint<> MTime,
  66. uint32_t User, uint32_t Group, uint64_t Size, file_type Type,
  67. perms Perms)
  68. : Name(Name), UID(UID), MTime(MTime), User(User), Group(Group), Size(Size),
  69. Type(Type), Perms(Perms) {}
  70. Status Status::copyWithNewName(const Status &In, StringRef NewName) {
  71. return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),
  72. In.getUser(), In.getGroup(), In.getSize(), In.getType(),
  73. In.getPermissions());
  74. }
  75. Status Status::copyWithNewName(const file_status &In, StringRef NewName) {
  76. return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),
  77. In.getUser(), In.getGroup(), In.getSize(), In.type(),
  78. In.permissions());
  79. }
  80. bool Status::equivalent(const Status &Other) const {
  81. assert(isStatusKnown() && Other.isStatusKnown());
  82. return getUniqueID() == Other.getUniqueID();
  83. }
  84. bool Status::isDirectory() const { return Type == file_type::directory_file; }
  85. bool Status::isRegularFile() const { return Type == file_type::regular_file; }
  86. bool Status::isOther() const {
  87. return exists() && !isRegularFile() && !isDirectory() && !isSymlink();
  88. }
  89. bool Status::isSymlink() const { return Type == file_type::symlink_file; }
  90. bool Status::isStatusKnown() const { return Type != file_type::status_error; }
  91. bool Status::exists() const {
  92. return isStatusKnown() && Type != file_type::file_not_found;
  93. }
  94. File::~File() = default;
  95. FileSystem::~FileSystem() = default;
  96. ErrorOr<std::unique_ptr<MemoryBuffer>>
  97. FileSystem::getBufferForFile(const llvm::Twine &Name, int64_t FileSize,
  98. bool RequiresNullTerminator, bool IsVolatile) {
  99. auto F = openFileForRead(Name);
  100. if (!F)
  101. return F.getError();
  102. return (*F)->getBuffer(Name, FileSize, RequiresNullTerminator, IsVolatile);
  103. }
  104. std::error_code FileSystem::makeAbsolute(SmallVectorImpl<char> &Path) const {
  105. if (llvm::sys::path::is_absolute(Path))
  106. return {};
  107. auto WorkingDir = getCurrentWorkingDirectory();
  108. if (!WorkingDir)
  109. return WorkingDir.getError();
  110. llvm::sys::fs::make_absolute(WorkingDir.get(), Path);
  111. return {};
  112. }
  113. std::error_code FileSystem::getRealPath(const Twine &Path,
  114. SmallVectorImpl<char> &Output) const {
  115. return errc::operation_not_permitted;
  116. }
  117. std::error_code FileSystem::isLocal(const Twine &Path, bool &Result) {
  118. return errc::operation_not_permitted;
  119. }
  120. bool FileSystem::exists(const Twine &Path) {
  121. auto Status = status(Path);
  122. return Status && Status->exists();
  123. }
  124. #ifndef NDEBUG
  125. static bool isTraversalComponent(StringRef Component) {
  126. return Component.equals("..") || Component.equals(".");
  127. }
  128. static bool pathHasTraversal(StringRef Path) {
  129. using namespace llvm::sys;
  130. for (StringRef Comp : llvm::make_range(path::begin(Path), path::end(Path)))
  131. if (isTraversalComponent(Comp))
  132. return true;
  133. return false;
  134. }
  135. #endif
  136. //===-----------------------------------------------------------------------===/
  137. // RealFileSystem implementation
  138. //===-----------------------------------------------------------------------===/
  139. namespace {
  140. /// Wrapper around a raw file descriptor.
  141. class RealFile : public File {
  142. friend class RealFileSystem;
  143. int FD;
  144. Status S;
  145. std::string RealName;
  146. RealFile(int FD, StringRef NewName, StringRef NewRealPathName)
  147. : FD(FD), S(NewName, {}, {}, {}, {}, {},
  148. llvm::sys::fs::file_type::status_error, {}),
  149. RealName(NewRealPathName.str()) {
  150. assert(FD >= 0 && "Invalid or inactive file descriptor");
  151. }
  152. public:
  153. ~RealFile() override;
  154. ErrorOr<Status> status() override;
  155. ErrorOr<std::string> getName() override;
  156. ErrorOr<std::unique_ptr<MemoryBuffer>> getBuffer(const Twine &Name,
  157. int64_t FileSize,
  158. bool RequiresNullTerminator,
  159. bool IsVolatile) override;
  160. std::error_code close() override;
  161. };
  162. } // namespace
  163. RealFile::~RealFile() { close(); }
  164. ErrorOr<Status> RealFile::status() {
  165. assert(FD != -1 && "cannot stat closed file");
  166. if (!S.isStatusKnown()) {
  167. file_status RealStatus;
  168. if (std::error_code EC = sys::fs::status(FD, RealStatus))
  169. return EC;
  170. S = Status::copyWithNewName(RealStatus, S.getName());
  171. }
  172. return S;
  173. }
  174. ErrorOr<std::string> RealFile::getName() {
  175. return RealName.empty() ? S.getName().str() : RealName;
  176. }
  177. ErrorOr<std::unique_ptr<MemoryBuffer>>
  178. RealFile::getBuffer(const Twine &Name, int64_t FileSize,
  179. bool RequiresNullTerminator, bool IsVolatile) {
  180. assert(FD != -1 && "cannot get buffer for closed file");
  181. return MemoryBuffer::getOpenFile(FD, Name, FileSize, RequiresNullTerminator,
  182. IsVolatile);
  183. }
  184. std::error_code RealFile::close() {
  185. std::error_code EC = sys::Process::SafelyCloseFileDescriptor(FD);
  186. FD = -1;
  187. return EC;
  188. }
  189. namespace {
  190. /// The file system according to your operating system.
  191. class RealFileSystem : public FileSystem {
  192. public:
  193. ErrorOr<Status> status(const Twine &Path) override;
  194. ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override;
  195. directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
  196. llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override;
  197. std::error_code setCurrentWorkingDirectory(const Twine &Path) override;
  198. std::error_code isLocal(const Twine &Path, bool &Result) override;
  199. std::error_code getRealPath(const Twine &Path,
  200. SmallVectorImpl<char> &Output) const override;
  201. private:
  202. mutable std::mutex CWDMutex;
  203. mutable std::string CWDCache;
  204. };
  205. } // namespace
  206. ErrorOr<Status> RealFileSystem::status(const Twine &Path) {
  207. sys::fs::file_status RealStatus;
  208. if (std::error_code EC = sys::fs::status(Path, RealStatus))
  209. return EC;
  210. return Status::copyWithNewName(RealStatus, Path.str());
  211. }
  212. ErrorOr<std::unique_ptr<File>>
  213. RealFileSystem::openFileForRead(const Twine &Name) {
  214. int FD;
  215. SmallString<256> RealName;
  216. if (std::error_code EC =
  217. sys::fs::openFileForRead(Name, FD, sys::fs::OF_None, &RealName))
  218. return EC;
  219. return std::unique_ptr<File>(new RealFile(FD, Name.str(), RealName.str()));
  220. }
  221. llvm::ErrorOr<std::string> RealFileSystem::getCurrentWorkingDirectory() const {
  222. std::lock_guard<std::mutex> Lock(CWDMutex);
  223. if (!CWDCache.empty())
  224. return CWDCache;
  225. SmallString<256> Dir;
  226. if (std::error_code EC = llvm::sys::fs::current_path(Dir))
  227. return EC;
  228. CWDCache = Dir.str();
  229. return CWDCache;
  230. }
  231. std::error_code RealFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
  232. // FIXME: chdir is thread hostile; on the other hand, creating the same
  233. // behavior as chdir is complex: chdir resolves the path once, thus
  234. // guaranteeing that all subsequent relative path operations work
  235. // on the same path the original chdir resulted in. This makes a
  236. // difference for example on network filesystems, where symlinks might be
  237. // switched during runtime of the tool. Fixing this depends on having a
  238. // file system abstraction that allows openat() style interactions.
  239. if (auto EC = llvm::sys::fs::set_current_path(Path))
  240. return EC;
  241. // Invalidate cache.
  242. std::lock_guard<std::mutex> Lock(CWDMutex);
  243. CWDCache.clear();
  244. return std::error_code();
  245. }
  246. std::error_code RealFileSystem::isLocal(const Twine &Path, bool &Result) {
  247. return llvm::sys::fs::is_local(Path, Result);
  248. }
  249. std::error_code
  250. RealFileSystem::getRealPath(const Twine &Path,
  251. SmallVectorImpl<char> &Output) const {
  252. return llvm::sys::fs::real_path(Path, Output);
  253. }
  254. IntrusiveRefCntPtr<FileSystem> vfs::getRealFileSystem() {
  255. static IntrusiveRefCntPtr<FileSystem> FS = new RealFileSystem();
  256. return FS;
  257. }
  258. namespace {
  259. class RealFSDirIter : public llvm::vfs::detail::DirIterImpl {
  260. llvm::sys::fs::directory_iterator Iter;
  261. public:
  262. RealFSDirIter(const Twine &Path, std::error_code &EC) : Iter(Path, EC) {
  263. if (Iter != llvm::sys::fs::directory_iterator())
  264. CurrentEntry = directory_entry(Iter->path(), Iter->type());
  265. }
  266. std::error_code increment() override {
  267. std::error_code EC;
  268. Iter.increment(EC);
  269. CurrentEntry = (Iter == llvm::sys::fs::directory_iterator())
  270. ? directory_entry()
  271. : directory_entry(Iter->path(), Iter->type());
  272. return EC;
  273. }
  274. };
  275. } // namespace
  276. directory_iterator RealFileSystem::dir_begin(const Twine &Dir,
  277. std::error_code &EC) {
  278. return directory_iterator(std::make_shared<RealFSDirIter>(Dir, EC));
  279. }
  280. //===-----------------------------------------------------------------------===/
  281. // OverlayFileSystem implementation
  282. //===-----------------------------------------------------------------------===/
  283. OverlayFileSystem::OverlayFileSystem(IntrusiveRefCntPtr<FileSystem> BaseFS) {
  284. FSList.push_back(std::move(BaseFS));
  285. }
  286. void OverlayFileSystem::pushOverlay(IntrusiveRefCntPtr<FileSystem> FS) {
  287. FSList.push_back(FS);
  288. // Synchronize added file systems by duplicating the working directory from
  289. // the first one in the list.
  290. FS->setCurrentWorkingDirectory(getCurrentWorkingDirectory().get());
  291. }
  292. ErrorOr<Status> OverlayFileSystem::status(const Twine &Path) {
  293. // FIXME: handle symlinks that cross file systems
  294. for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) {
  295. ErrorOr<Status> Status = (*I)->status(Path);
  296. if (Status || Status.getError() != llvm::errc::no_such_file_or_directory)
  297. return Status;
  298. }
  299. return make_error_code(llvm::errc::no_such_file_or_directory);
  300. }
  301. ErrorOr<std::unique_ptr<File>>
  302. OverlayFileSystem::openFileForRead(const llvm::Twine &Path) {
  303. // FIXME: handle symlinks that cross file systems
  304. for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) {
  305. auto Result = (*I)->openFileForRead(Path);
  306. if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
  307. return Result;
  308. }
  309. return make_error_code(llvm::errc::no_such_file_or_directory);
  310. }
  311. llvm::ErrorOr<std::string>
  312. OverlayFileSystem::getCurrentWorkingDirectory() const {
  313. // All file systems are synchronized, just take the first working directory.
  314. return FSList.front()->getCurrentWorkingDirectory();
  315. }
  316. std::error_code
  317. OverlayFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
  318. for (auto &FS : FSList)
  319. if (std::error_code EC = FS->setCurrentWorkingDirectory(Path))
  320. return EC;
  321. return {};
  322. }
  323. std::error_code OverlayFileSystem::isLocal(const Twine &Path, bool &Result) {
  324. for (auto &FS : FSList)
  325. if (FS->exists(Path))
  326. return FS->isLocal(Path, Result);
  327. return errc::no_such_file_or_directory;
  328. }
  329. std::error_code
  330. OverlayFileSystem::getRealPath(const Twine &Path,
  331. SmallVectorImpl<char> &Output) const {
  332. for (auto &FS : FSList)
  333. if (FS->exists(Path))
  334. return FS->getRealPath(Path, Output);
  335. return errc::no_such_file_or_directory;
  336. }
  337. llvm::vfs::detail::DirIterImpl::~DirIterImpl() = default;
  338. namespace {
  339. class OverlayFSDirIterImpl : public llvm::vfs::detail::DirIterImpl {
  340. OverlayFileSystem &Overlays;
  341. std::string Path;
  342. OverlayFileSystem::iterator CurrentFS;
  343. directory_iterator CurrentDirIter;
  344. llvm::StringSet<> SeenNames;
  345. std::error_code incrementFS() {
  346. assert(CurrentFS != Overlays.overlays_end() && "incrementing past end");
  347. ++CurrentFS;
  348. for (auto E = Overlays.overlays_end(); CurrentFS != E; ++CurrentFS) {
  349. std::error_code EC;
  350. CurrentDirIter = (*CurrentFS)->dir_begin(Path, EC);
  351. if (EC && EC != errc::no_such_file_or_directory)
  352. return EC;
  353. if (CurrentDirIter != directory_iterator())
  354. break; // found
  355. }
  356. return {};
  357. }
  358. std::error_code incrementDirIter(bool IsFirstTime) {
  359. assert((IsFirstTime || CurrentDirIter != directory_iterator()) &&
  360. "incrementing past end");
  361. std::error_code EC;
  362. if (!IsFirstTime)
  363. CurrentDirIter.increment(EC);
  364. if (!EC && CurrentDirIter == directory_iterator())
  365. EC = incrementFS();
  366. return EC;
  367. }
  368. std::error_code incrementImpl(bool IsFirstTime) {
  369. while (true) {
  370. std::error_code EC = incrementDirIter(IsFirstTime);
  371. if (EC || CurrentDirIter == directory_iterator()) {
  372. CurrentEntry = directory_entry();
  373. return EC;
  374. }
  375. CurrentEntry = *CurrentDirIter;
  376. StringRef Name = llvm::sys::path::filename(CurrentEntry.path());
  377. if (SeenNames.insert(Name).second)
  378. return EC; // name not seen before
  379. }
  380. llvm_unreachable("returned above");
  381. }
  382. public:
  383. OverlayFSDirIterImpl(const Twine &Path, OverlayFileSystem &FS,
  384. std::error_code &EC)
  385. : Overlays(FS), Path(Path.str()), CurrentFS(Overlays.overlays_begin()) {
  386. CurrentDirIter = (*CurrentFS)->dir_begin(Path, EC);
  387. EC = incrementImpl(true);
  388. }
  389. std::error_code increment() override { return incrementImpl(false); }
  390. };
  391. } // namespace
  392. directory_iterator OverlayFileSystem::dir_begin(const Twine &Dir,
  393. std::error_code &EC) {
  394. return directory_iterator(
  395. std::make_shared<OverlayFSDirIterImpl>(Dir, *this, EC));
  396. }
  397. void ProxyFileSystem::anchor() {}
  398. namespace llvm {
  399. namespace vfs {
  400. namespace detail {
  401. enum InMemoryNodeKind { IME_File, IME_Directory, IME_HardLink };
  402. /// The in memory file system is a tree of Nodes. Every node can either be a
  403. /// file , hardlink or a directory.
  404. class InMemoryNode {
  405. InMemoryNodeKind Kind;
  406. std::string FileName;
  407. public:
  408. InMemoryNode(llvm::StringRef FileName, InMemoryNodeKind Kind)
  409. : Kind(Kind), FileName(llvm::sys::path::filename(FileName)) {}
  410. virtual ~InMemoryNode() = default;
  411. /// Get the filename of this node (the name without the directory part).
  412. StringRef getFileName() const { return FileName; }
  413. InMemoryNodeKind getKind() const { return Kind; }
  414. virtual std::string toString(unsigned Indent) const = 0;
  415. };
  416. class InMemoryFile : public InMemoryNode {
  417. Status Stat;
  418. std::unique_ptr<llvm::MemoryBuffer> Buffer;
  419. public:
  420. InMemoryFile(Status Stat, std::unique_ptr<llvm::MemoryBuffer> Buffer)
  421. : InMemoryNode(Stat.getName(), IME_File), Stat(std::move(Stat)),
  422. Buffer(std::move(Buffer)) {}
  423. /// Return the \p Status for this node. \p RequestedName should be the name
  424. /// through which the caller referred to this node. It will override
  425. /// \p Status::Name in the return value, to mimic the behavior of \p RealFile.
  426. Status getStatus(StringRef RequestedName) const {
  427. return Status::copyWithNewName(Stat, RequestedName);
  428. }
  429. llvm::MemoryBuffer *getBuffer() const { return Buffer.get(); }
  430. std::string toString(unsigned Indent) const override {
  431. return (std::string(Indent, ' ') + Stat.getName() + "\n").str();
  432. }
  433. static bool classof(const InMemoryNode *N) {
  434. return N->getKind() == IME_File;
  435. }
  436. };
  437. namespace {
  438. class InMemoryHardLink : public InMemoryNode {
  439. const InMemoryFile &ResolvedFile;
  440. public:
  441. InMemoryHardLink(StringRef Path, const InMemoryFile &ResolvedFile)
  442. : InMemoryNode(Path, IME_HardLink), ResolvedFile(ResolvedFile) {}
  443. const InMemoryFile &getResolvedFile() const { return ResolvedFile; }
  444. std::string toString(unsigned Indent) const override {
  445. return std::string(Indent, ' ') + "HardLink to -> " +
  446. ResolvedFile.toString(0);
  447. }
  448. static bool classof(const InMemoryNode *N) {
  449. return N->getKind() == IME_HardLink;
  450. }
  451. };
  452. /// Adapt a InMemoryFile for VFS' File interface. The goal is to make
  453. /// \p InMemoryFileAdaptor mimic as much as possible the behavior of
  454. /// \p RealFile.
  455. class InMemoryFileAdaptor : public File {
  456. const InMemoryFile &Node;
  457. /// The name to use when returning a Status for this file.
  458. std::string RequestedName;
  459. public:
  460. explicit InMemoryFileAdaptor(const InMemoryFile &Node,
  461. std::string RequestedName)
  462. : Node(Node), RequestedName(std::move(RequestedName)) {}
  463. llvm::ErrorOr<Status> status() override {
  464. return Node.getStatus(RequestedName);
  465. }
  466. llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
  467. getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
  468. bool IsVolatile) override {
  469. llvm::MemoryBuffer *Buf = Node.getBuffer();
  470. return llvm::MemoryBuffer::getMemBuffer(
  471. Buf->getBuffer(), Buf->getBufferIdentifier(), RequiresNullTerminator);
  472. }
  473. std::error_code close() override { return {}; }
  474. };
  475. } // namespace
  476. class InMemoryDirectory : public InMemoryNode {
  477. Status Stat;
  478. llvm::StringMap<std::unique_ptr<InMemoryNode>> Entries;
  479. public:
  480. InMemoryDirectory(Status Stat)
  481. : InMemoryNode(Stat.getName(), IME_Directory), Stat(std::move(Stat)) {}
  482. /// Return the \p Status for this node. \p RequestedName should be the name
  483. /// through which the caller referred to this node. It will override
  484. /// \p Status::Name in the return value, to mimic the behavior of \p RealFile.
  485. Status getStatus(StringRef RequestedName) const {
  486. return Status::copyWithNewName(Stat, RequestedName);
  487. }
  488. InMemoryNode *getChild(StringRef Name) {
  489. auto I = Entries.find(Name);
  490. if (I != Entries.end())
  491. return I->second.get();
  492. return nullptr;
  493. }
  494. InMemoryNode *addChild(StringRef Name, std::unique_ptr<InMemoryNode> Child) {
  495. return Entries.insert(make_pair(Name, std::move(Child)))
  496. .first->second.get();
  497. }
  498. using const_iterator = decltype(Entries)::const_iterator;
  499. const_iterator begin() const { return Entries.begin(); }
  500. const_iterator end() const { return Entries.end(); }
  501. std::string toString(unsigned Indent) const override {
  502. std::string Result =
  503. (std::string(Indent, ' ') + Stat.getName() + "\n").str();
  504. for (const auto &Entry : Entries)
  505. Result += Entry.second->toString(Indent + 2);
  506. return Result;
  507. }
  508. static bool classof(const InMemoryNode *N) {
  509. return N->getKind() == IME_Directory;
  510. }
  511. };
  512. namespace {
  513. Status getNodeStatus(const InMemoryNode *Node, StringRef RequestedName) {
  514. if (auto Dir = dyn_cast<detail::InMemoryDirectory>(Node))
  515. return Dir->getStatus(RequestedName);
  516. if (auto File = dyn_cast<detail::InMemoryFile>(Node))
  517. return File->getStatus(RequestedName);
  518. if (auto Link = dyn_cast<detail::InMemoryHardLink>(Node))
  519. return Link->getResolvedFile().getStatus(RequestedName);
  520. llvm_unreachable("Unknown node type");
  521. }
  522. } // namespace
  523. } // namespace detail
  524. InMemoryFileSystem::InMemoryFileSystem(bool UseNormalizedPaths)
  525. : Root(new detail::InMemoryDirectory(
  526. Status("", getNextVirtualUniqueID(), llvm::sys::TimePoint<>(), 0, 0,
  527. 0, llvm::sys::fs::file_type::directory_file,
  528. llvm::sys::fs::perms::all_all))),
  529. UseNormalizedPaths(UseNormalizedPaths) {}
  530. InMemoryFileSystem::~InMemoryFileSystem() = default;
  531. std::string InMemoryFileSystem::toString() const {
  532. return Root->toString(/*Indent=*/0);
  533. }
  534. bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime,
  535. std::unique_ptr<llvm::MemoryBuffer> Buffer,
  536. Optional<uint32_t> User,
  537. Optional<uint32_t> Group,
  538. Optional<llvm::sys::fs::file_type> Type,
  539. Optional<llvm::sys::fs::perms> Perms,
  540. const detail::InMemoryFile *HardLinkTarget) {
  541. SmallString<128> Path;
  542. P.toVector(Path);
  543. // Fix up relative paths. This just prepends the current working directory.
  544. std::error_code EC = makeAbsolute(Path);
  545. assert(!EC);
  546. (void)EC;
  547. if (useNormalizedPaths())
  548. llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
  549. if (Path.empty())
  550. return false;
  551. detail::InMemoryDirectory *Dir = Root.get();
  552. auto I = llvm::sys::path::begin(Path), E = sys::path::end(Path);
  553. const auto ResolvedUser = User.getValueOr(0);
  554. const auto ResolvedGroup = Group.getValueOr(0);
  555. const auto ResolvedType = Type.getValueOr(sys::fs::file_type::regular_file);
  556. const auto ResolvedPerms = Perms.getValueOr(sys::fs::all_all);
  557. assert(!(HardLinkTarget && Buffer) && "HardLink cannot have a buffer");
  558. // Any intermediate directories we create should be accessible by
  559. // the owner, even if Perms says otherwise for the final path.
  560. const auto NewDirectoryPerms = ResolvedPerms | sys::fs::owner_all;
  561. while (true) {
  562. StringRef Name = *I;
  563. detail::InMemoryNode *Node = Dir->getChild(Name);
  564. ++I;
  565. if (!Node) {
  566. if (I == E) {
  567. // End of the path.
  568. std::unique_ptr<detail::InMemoryNode> Child;
  569. if (HardLinkTarget)
  570. Child.reset(new detail::InMemoryHardLink(P.str(), *HardLinkTarget));
  571. else {
  572. // Create a new file or directory.
  573. Status Stat(P.str(), getNextVirtualUniqueID(),
  574. llvm::sys::toTimePoint(ModificationTime), ResolvedUser,
  575. ResolvedGroup, Buffer->getBufferSize(), ResolvedType,
  576. ResolvedPerms);
  577. if (ResolvedType == sys::fs::file_type::directory_file) {
  578. Child.reset(new detail::InMemoryDirectory(std::move(Stat)));
  579. } else {
  580. Child.reset(
  581. new detail::InMemoryFile(std::move(Stat), std::move(Buffer)));
  582. }
  583. }
  584. Dir->addChild(Name, std::move(Child));
  585. return true;
  586. }
  587. // Create a new directory. Use the path up to here.
  588. Status Stat(
  589. StringRef(Path.str().begin(), Name.end() - Path.str().begin()),
  590. getNextVirtualUniqueID(), llvm::sys::toTimePoint(ModificationTime),
  591. ResolvedUser, ResolvedGroup, 0, sys::fs::file_type::directory_file,
  592. NewDirectoryPerms);
  593. Dir = cast<detail::InMemoryDirectory>(Dir->addChild(
  594. Name, llvm::make_unique<detail::InMemoryDirectory>(std::move(Stat))));
  595. continue;
  596. }
  597. if (auto *NewDir = dyn_cast<detail::InMemoryDirectory>(Node)) {
  598. Dir = NewDir;
  599. } else {
  600. assert((isa<detail::InMemoryFile>(Node) ||
  601. isa<detail::InMemoryHardLink>(Node)) &&
  602. "Must be either file, hardlink or directory!");
  603. // Trying to insert a directory in place of a file.
  604. if (I != E)
  605. return false;
  606. // Return false only if the new file is different from the existing one.
  607. if (auto Link = dyn_cast<detail::InMemoryHardLink>(Node)) {
  608. return Link->getResolvedFile().getBuffer()->getBuffer() ==
  609. Buffer->getBuffer();
  610. }
  611. return cast<detail::InMemoryFile>(Node)->getBuffer()->getBuffer() ==
  612. Buffer->getBuffer();
  613. }
  614. }
  615. }
  616. bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime,
  617. std::unique_ptr<llvm::MemoryBuffer> Buffer,
  618. Optional<uint32_t> User,
  619. Optional<uint32_t> Group,
  620. Optional<llvm::sys::fs::file_type> Type,
  621. Optional<llvm::sys::fs::perms> Perms) {
  622. return addFile(P, ModificationTime, std::move(Buffer), User, Group, Type,
  623. Perms, /*HardLinkTarget=*/nullptr);
  624. }
  625. bool InMemoryFileSystem::addFileNoOwn(const Twine &P, time_t ModificationTime,
  626. llvm::MemoryBuffer *Buffer,
  627. Optional<uint32_t> User,
  628. Optional<uint32_t> Group,
  629. Optional<llvm::sys::fs::file_type> Type,
  630. Optional<llvm::sys::fs::perms> Perms) {
  631. return addFile(P, ModificationTime,
  632. llvm::MemoryBuffer::getMemBuffer(
  633. Buffer->getBuffer(), Buffer->getBufferIdentifier()),
  634. std::move(User), std::move(Group), std::move(Type),
  635. std::move(Perms));
  636. }
  637. static ErrorOr<const detail::InMemoryNode *>
  638. lookupInMemoryNode(const InMemoryFileSystem &FS, detail::InMemoryDirectory *Dir,
  639. const Twine &P) {
  640. SmallString<128> Path;
  641. P.toVector(Path);
  642. // Fix up relative paths. This just prepends the current working directory.
  643. std::error_code EC = FS.makeAbsolute(Path);
  644. assert(!EC);
  645. (void)EC;
  646. if (FS.useNormalizedPaths())
  647. llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
  648. if (Path.empty())
  649. return Dir;
  650. auto I = llvm::sys::path::begin(Path), E = llvm::sys::path::end(Path);
  651. while (true) {
  652. detail::InMemoryNode *Node = Dir->getChild(*I);
  653. ++I;
  654. if (!Node)
  655. return errc::no_such_file_or_directory;
  656. // Return the file if it's at the end of the path.
  657. if (auto File = dyn_cast<detail::InMemoryFile>(Node)) {
  658. if (I == E)
  659. return File;
  660. return errc::no_such_file_or_directory;
  661. }
  662. // If Node is HardLink then return the resolved file.
  663. if (auto File = dyn_cast<detail::InMemoryHardLink>(Node)) {
  664. if (I == E)
  665. return &File->getResolvedFile();
  666. return errc::no_such_file_or_directory;
  667. }
  668. // Traverse directories.
  669. Dir = cast<detail::InMemoryDirectory>(Node);
  670. if (I == E)
  671. return Dir;
  672. }
  673. }
  674. bool InMemoryFileSystem::addHardLink(const Twine &FromPath,
  675. const Twine &ToPath) {
  676. auto FromNode = lookupInMemoryNode(*this, Root.get(), FromPath);
  677. auto ToNode = lookupInMemoryNode(*this, Root.get(), ToPath);
  678. // FromPath must not have been added before. ToPath must have been added
  679. // before. Resolved ToPath must be a File.
  680. if (!ToNode || FromNode || !isa<detail::InMemoryFile>(*ToNode))
  681. return false;
  682. return this->addFile(FromPath, 0, nullptr, None, None, None, None,
  683. cast<detail::InMemoryFile>(*ToNode));
  684. }
  685. llvm::ErrorOr<Status> InMemoryFileSystem::status(const Twine &Path) {
  686. auto Node = lookupInMemoryNode(*this, Root.get(), Path);
  687. if (Node)
  688. return detail::getNodeStatus(*Node, Path.str());
  689. return Node.getError();
  690. }
  691. llvm::ErrorOr<std::unique_ptr<File>>
  692. InMemoryFileSystem::openFileForRead(const Twine &Path) {
  693. auto Node = lookupInMemoryNode(*this, Root.get(), Path);
  694. if (!Node)
  695. return Node.getError();
  696. // When we have a file provide a heap-allocated wrapper for the memory buffer
  697. // to match the ownership semantics for File.
  698. if (auto *F = dyn_cast<detail::InMemoryFile>(*Node))
  699. return std::unique_ptr<File>(
  700. new detail::InMemoryFileAdaptor(*F, Path.str()));
  701. // FIXME: errc::not_a_file?
  702. return make_error_code(llvm::errc::invalid_argument);
  703. }
  704. namespace {
  705. /// Adaptor from InMemoryDir::iterator to directory_iterator.
  706. class InMemoryDirIterator : public llvm::vfs::detail::DirIterImpl {
  707. detail::InMemoryDirectory::const_iterator I;
  708. detail::InMemoryDirectory::const_iterator E;
  709. std::string RequestedDirName;
  710. void setCurrentEntry() {
  711. if (I != E) {
  712. SmallString<256> Path(RequestedDirName);
  713. llvm::sys::path::append(Path, I->second->getFileName());
  714. sys::fs::file_type Type;
  715. switch (I->second->getKind()) {
  716. case detail::IME_File:
  717. case detail::IME_HardLink:
  718. Type = sys::fs::file_type::regular_file;
  719. break;
  720. case detail::IME_Directory:
  721. Type = sys::fs::file_type::directory_file;
  722. break;
  723. }
  724. CurrentEntry = directory_entry(Path.str(), Type);
  725. } else {
  726. // When we're at the end, make CurrentEntry invalid and DirIterImpl will
  727. // do the rest.
  728. CurrentEntry = directory_entry();
  729. }
  730. }
  731. public:
  732. InMemoryDirIterator() = default;
  733. explicit InMemoryDirIterator(const detail::InMemoryDirectory &Dir,
  734. std::string RequestedDirName)
  735. : I(Dir.begin()), E(Dir.end()),
  736. RequestedDirName(std::move(RequestedDirName)) {
  737. setCurrentEntry();
  738. }
  739. std::error_code increment() override {
  740. ++I;
  741. setCurrentEntry();
  742. return {};
  743. }
  744. };
  745. } // namespace
  746. directory_iterator InMemoryFileSystem::dir_begin(const Twine &Dir,
  747. std::error_code &EC) {
  748. auto Node = lookupInMemoryNode(*this, Root.get(), Dir);
  749. if (!Node) {
  750. EC = Node.getError();
  751. return directory_iterator(std::make_shared<InMemoryDirIterator>());
  752. }
  753. if (auto *DirNode = dyn_cast<detail::InMemoryDirectory>(*Node))
  754. return directory_iterator(
  755. std::make_shared<InMemoryDirIterator>(*DirNode, Dir.str()));
  756. EC = make_error_code(llvm::errc::not_a_directory);
  757. return directory_iterator(std::make_shared<InMemoryDirIterator>());
  758. }
  759. std::error_code InMemoryFileSystem::setCurrentWorkingDirectory(const Twine &P) {
  760. SmallString<128> Path;
  761. P.toVector(Path);
  762. // Fix up relative paths. This just prepends the current working directory.
  763. std::error_code EC = makeAbsolute(Path);
  764. assert(!EC);
  765. (void)EC;
  766. if (useNormalizedPaths())
  767. llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
  768. if (!Path.empty())
  769. WorkingDirectory = Path.str();
  770. return {};
  771. }
  772. std::error_code
  773. InMemoryFileSystem::getRealPath(const Twine &Path,
  774. SmallVectorImpl<char> &Output) const {
  775. auto CWD = getCurrentWorkingDirectory();
  776. if (!CWD || CWD->empty())
  777. return errc::operation_not_permitted;
  778. Path.toVector(Output);
  779. if (auto EC = makeAbsolute(Output))
  780. return EC;
  781. llvm::sys::path::remove_dots(Output, /*remove_dot_dot=*/true);
  782. return {};
  783. }
  784. std::error_code InMemoryFileSystem::isLocal(const Twine &Path, bool &Result) {
  785. Result = false;
  786. return {};
  787. }
  788. } // namespace vfs
  789. } // namespace llvm
  790. //===-----------------------------------------------------------------------===/
  791. // RedirectingFileSystem implementation
  792. //===-----------------------------------------------------------------------===/
  793. // FIXME: reuse implementation common with OverlayFSDirIterImpl as these
  794. // iterators are conceptually similar.
  795. class llvm::vfs::VFSFromYamlDirIterImpl
  796. : public llvm::vfs::detail::DirIterImpl {
  797. std::string Dir;
  798. RedirectingFileSystem::RedirectingDirectoryEntry::iterator Current, End;
  799. // To handle 'fallthrough' mode we need to iterate at first through
  800. // RedirectingDirectoryEntry and then through ExternalFS. These operations are
  801. // done sequentially, we just need to keep a track of what kind of iteration
  802. // we are currently performing.
  803. /// Flag telling if we should iterate through ExternalFS or stop at the last
  804. /// RedirectingDirectoryEntry::iterator.
  805. bool IterateExternalFS;
  806. /// Flag telling if we have switched to iterating through ExternalFS.
  807. bool IsExternalFSCurrent = false;
  808. FileSystem &ExternalFS;
  809. directory_iterator ExternalDirIter;
  810. llvm::StringSet<> SeenNames;
  811. /// To combine multiple iterations, different methods are responsible for
  812. /// different iteration steps.
  813. /// @{
  814. /// Responsible for dispatching between RedirectingDirectoryEntry iteration
  815. /// and ExternalFS iteration.
  816. std::error_code incrementImpl(bool IsFirstTime);
  817. /// Responsible for RedirectingDirectoryEntry iteration.
  818. std::error_code incrementContent(bool IsFirstTime);
  819. /// Responsible for ExternalFS iteration.
  820. std::error_code incrementExternal();
  821. /// @}
  822. public:
  823. VFSFromYamlDirIterImpl(
  824. const Twine &Path,
  825. RedirectingFileSystem::RedirectingDirectoryEntry::iterator Begin,
  826. RedirectingFileSystem::RedirectingDirectoryEntry::iterator End,
  827. bool IterateExternalFS, FileSystem &ExternalFS, std::error_code &EC);
  828. std::error_code increment() override;
  829. };
  830. llvm::ErrorOr<std::string>
  831. RedirectingFileSystem::getCurrentWorkingDirectory() const {
  832. return ExternalFS->getCurrentWorkingDirectory();
  833. }
  834. std::error_code
  835. RedirectingFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
  836. return ExternalFS->setCurrentWorkingDirectory(Path);
  837. }
  838. std::error_code RedirectingFileSystem::isLocal(const Twine &Path,
  839. bool &Result) {
  840. return ExternalFS->isLocal(Path, Result);
  841. }
  842. directory_iterator RedirectingFileSystem::dir_begin(const Twine &Dir,
  843. std::error_code &EC) {
  844. ErrorOr<RedirectingFileSystem::Entry *> E = lookupPath(Dir);
  845. if (!E) {
  846. EC = E.getError();
  847. if (IsFallthrough && EC == errc::no_such_file_or_directory)
  848. return ExternalFS->dir_begin(Dir, EC);
  849. return {};
  850. }
  851. ErrorOr<Status> S = status(Dir, *E);
  852. if (!S) {
  853. EC = S.getError();
  854. return {};
  855. }
  856. if (!S->isDirectory()) {
  857. EC = std::error_code(static_cast<int>(errc::not_a_directory),
  858. std::system_category());
  859. return {};
  860. }
  861. auto *D = cast<RedirectingFileSystem::RedirectingDirectoryEntry>(*E);
  862. return directory_iterator(std::make_shared<VFSFromYamlDirIterImpl>(
  863. Dir, D->contents_begin(), D->contents_end(),
  864. /*IterateExternalFS=*/IsFallthrough, *ExternalFS, EC));
  865. }
  866. void RedirectingFileSystem::setExternalContentsPrefixDir(StringRef PrefixDir) {
  867. ExternalContentsPrefixDir = PrefixDir.str();
  868. }
  869. StringRef RedirectingFileSystem::getExternalContentsPrefixDir() const {
  870. return ExternalContentsPrefixDir;
  871. }
  872. #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
  873. LLVM_DUMP_METHOD void RedirectingFileSystem::dump() const {
  874. for (const auto &Root : Roots)
  875. dumpEntry(Root.get());
  876. }
  877. LLVM_DUMP_METHOD void
  878. RedirectingFileSystem::dumpEntry(RedirectingFileSystem::Entry *E,
  879. int NumSpaces) const {
  880. StringRef Name = E->getName();
  881. for (int i = 0, e = NumSpaces; i < e; ++i)
  882. dbgs() << " ";
  883. dbgs() << "'" << Name.str().c_str() << "'"
  884. << "\n";
  885. if (E->getKind() == RedirectingFileSystem::EK_Directory) {
  886. auto *DE = dyn_cast<RedirectingFileSystem::RedirectingDirectoryEntry>(E);
  887. assert(DE && "Should be a directory");
  888. for (std::unique_ptr<Entry> &SubEntry :
  889. llvm::make_range(DE->contents_begin(), DE->contents_end()))
  890. dumpEntry(SubEntry.get(), NumSpaces + 2);
  891. }
  892. }
  893. #endif
  894. /// A helper class to hold the common YAML parsing state.
  895. class llvm::vfs::RedirectingFileSystemParser {
  896. yaml::Stream &Stream;
  897. void error(yaml::Node *N, const Twine &Msg) { Stream.printError(N, Msg); }
  898. // false on error
  899. bool parseScalarString(yaml::Node *N, StringRef &Result,
  900. SmallVectorImpl<char> &Storage) {
  901. const auto *S = dyn_cast<yaml::ScalarNode>(N);
  902. if (!S) {
  903. error(N, "expected string");
  904. return false;
  905. }
  906. Result = S->getValue(Storage);
  907. return true;
  908. }
  909. // false on error
  910. bool parseScalarBool(yaml::Node *N, bool &Result) {
  911. SmallString<5> Storage;
  912. StringRef Value;
  913. if (!parseScalarString(N, Value, Storage))
  914. return false;
  915. if (Value.equals_lower("true") || Value.equals_lower("on") ||
  916. Value.equals_lower("yes") || Value == "1") {
  917. Result = true;
  918. return true;
  919. } else if (Value.equals_lower("false") || Value.equals_lower("off") ||
  920. Value.equals_lower("no") || Value == "0") {
  921. Result = false;
  922. return true;
  923. }
  924. error(N, "expected boolean value");
  925. return false;
  926. }
  927. struct KeyStatus {
  928. bool Required;
  929. bool Seen = false;
  930. KeyStatus(bool Required = false) : Required(Required) {}
  931. };
  932. using KeyStatusPair = std::pair<StringRef, KeyStatus>;
  933. // false on error
  934. bool checkDuplicateOrUnknownKey(yaml::Node *KeyNode, StringRef Key,
  935. DenseMap<StringRef, KeyStatus> &Keys) {
  936. if (!Keys.count(Key)) {
  937. error(KeyNode, "unknown key");
  938. return false;
  939. }
  940. KeyStatus &S = Keys[Key];
  941. if (S.Seen) {
  942. error(KeyNode, Twine("duplicate key '") + Key + "'");
  943. return false;
  944. }
  945. S.Seen = true;
  946. return true;
  947. }
  948. // false on error
  949. bool checkMissingKeys(yaml::Node *Obj, DenseMap<StringRef, KeyStatus> &Keys) {
  950. for (const auto &I : Keys) {
  951. if (I.second.Required && !I.second.Seen) {
  952. error(Obj, Twine("missing key '") + I.first + "'");
  953. return false;
  954. }
  955. }
  956. return true;
  957. }
  958. RedirectingFileSystem::Entry *
  959. lookupOrCreateEntry(RedirectingFileSystem *FS, StringRef Name,
  960. RedirectingFileSystem::Entry *ParentEntry = nullptr) {
  961. if (!ParentEntry) { // Look for a existent root
  962. for (const auto &Root : FS->Roots) {
  963. if (Name.equals(Root->getName())) {
  964. ParentEntry = Root.get();
  965. return ParentEntry;
  966. }
  967. }
  968. } else { // Advance to the next component
  969. auto *DE = dyn_cast<RedirectingFileSystem::RedirectingDirectoryEntry>(
  970. ParentEntry);
  971. for (std::unique_ptr<RedirectingFileSystem::Entry> &Content :
  972. llvm::make_range(DE->contents_begin(), DE->contents_end())) {
  973. auto *DirContent =
  974. dyn_cast<RedirectingFileSystem::RedirectingDirectoryEntry>(
  975. Content.get());
  976. if (DirContent && Name.equals(Content->getName()))
  977. return DirContent;
  978. }
  979. }
  980. // ... or create a new one
  981. std::unique_ptr<RedirectingFileSystem::Entry> E =
  982. llvm::make_unique<RedirectingFileSystem::RedirectingDirectoryEntry>(
  983. Name, Status("", getNextVirtualUniqueID(),
  984. std::chrono::system_clock::now(), 0, 0, 0,
  985. file_type::directory_file, sys::fs::all_all));
  986. if (!ParentEntry) { // Add a new root to the overlay
  987. FS->Roots.push_back(std::move(E));
  988. ParentEntry = FS->Roots.back().get();
  989. return ParentEntry;
  990. }
  991. auto *DE =
  992. dyn_cast<RedirectingFileSystem::RedirectingDirectoryEntry>(ParentEntry);
  993. DE->addContent(std::move(E));
  994. return DE->getLastContent();
  995. }
  996. void uniqueOverlayTree(RedirectingFileSystem *FS,
  997. RedirectingFileSystem::Entry *SrcE,
  998. RedirectingFileSystem::Entry *NewParentE = nullptr) {
  999. StringRef Name = SrcE->getName();
  1000. switch (SrcE->getKind()) {
  1001. case RedirectingFileSystem::EK_Directory: {
  1002. auto *DE =
  1003. dyn_cast<RedirectingFileSystem::RedirectingDirectoryEntry>(SrcE);
  1004. assert(DE && "Must be a directory");
  1005. // Empty directories could be present in the YAML as a way to
  1006. // describe a file for a current directory after some of its subdir
  1007. // is parsed. This only leads to redundant walks, ignore it.
  1008. if (!Name.empty())
  1009. NewParentE = lookupOrCreateEntry(FS, Name, NewParentE);
  1010. for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
  1011. llvm::make_range(DE->contents_begin(), DE->contents_end()))
  1012. uniqueOverlayTree(FS, SubEntry.get(), NewParentE);
  1013. break;
  1014. }
  1015. case RedirectingFileSystem::EK_File: {
  1016. auto *FE = dyn_cast<RedirectingFileSystem::RedirectingFileEntry>(SrcE);
  1017. assert(FE && "Must be a file");
  1018. assert(NewParentE && "Parent entry must exist");
  1019. auto *DE = dyn_cast<RedirectingFileSystem::RedirectingDirectoryEntry>(
  1020. NewParentE);
  1021. DE->addContent(
  1022. llvm::make_unique<RedirectingFileSystem::RedirectingFileEntry>(
  1023. Name, FE->getExternalContentsPath(), FE->getUseName()));
  1024. break;
  1025. }
  1026. }
  1027. }
  1028. std::unique_ptr<RedirectingFileSystem::Entry>
  1029. parseEntry(yaml::Node *N, RedirectingFileSystem *FS, bool IsRootEntry) {
  1030. auto *M = dyn_cast<yaml::MappingNode>(N);
  1031. if (!M) {
  1032. error(N, "expected mapping node for file or directory entry");
  1033. return nullptr;
  1034. }
  1035. KeyStatusPair Fields[] = {
  1036. KeyStatusPair("name", true),
  1037. KeyStatusPair("type", true),
  1038. KeyStatusPair("contents", false),
  1039. KeyStatusPair("external-contents", false),
  1040. KeyStatusPair("use-external-name", false),
  1041. };
  1042. DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields));
  1043. bool HasContents = false; // external or otherwise
  1044. std::vector<std::unique_ptr<RedirectingFileSystem::Entry>>
  1045. EntryArrayContents;
  1046. std::string ExternalContentsPath;
  1047. std::string Name;
  1048. yaml::Node *NameValueNode;
  1049. auto UseExternalName =
  1050. RedirectingFileSystem::RedirectingFileEntry::NK_NotSet;
  1051. RedirectingFileSystem::EntryKind Kind;
  1052. for (auto &I : *M) {
  1053. StringRef Key;
  1054. // Reuse the buffer for key and value, since we don't look at key after
  1055. // parsing value.
  1056. SmallString<256> Buffer;
  1057. if (!parseScalarString(I.getKey(), Key, Buffer))
  1058. return nullptr;
  1059. if (!checkDuplicateOrUnknownKey(I.getKey(), Key, Keys))
  1060. return nullptr;
  1061. StringRef Value;
  1062. if (Key == "name") {
  1063. if (!parseScalarString(I.getValue(), Value, Buffer))
  1064. return nullptr;
  1065. NameValueNode = I.getValue();
  1066. if (FS->UseCanonicalizedPaths) {
  1067. SmallString<256> Path(Value);
  1068. // Guarantee that old YAML files containing paths with ".." and "."
  1069. // are properly canonicalized before read into the VFS.
  1070. Path = sys::path::remove_leading_dotslash(Path);
  1071. sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
  1072. Name = Path.str();
  1073. } else {
  1074. Name = Value;
  1075. }
  1076. } else if (Key == "type") {
  1077. if (!parseScalarString(I.getValue(), Value, Buffer))
  1078. return nullptr;
  1079. if (Value == "file")
  1080. Kind = RedirectingFileSystem::EK_File;
  1081. else if (Value == "directory")
  1082. Kind = RedirectingFileSystem::EK_Directory;
  1083. else {
  1084. error(I.getValue(), "unknown value for 'type'");
  1085. return nullptr;
  1086. }
  1087. } else if (Key == "contents") {
  1088. if (HasContents) {
  1089. error(I.getKey(),
  1090. "entry already has 'contents' or 'external-contents'");
  1091. return nullptr;
  1092. }
  1093. HasContents = true;
  1094. auto *Contents = dyn_cast<yaml::SequenceNode>(I.getValue());
  1095. if (!Contents) {
  1096. // FIXME: this is only for directories, what about files?
  1097. error(I.getValue(), "expected array");
  1098. return nullptr;
  1099. }
  1100. for (auto &I : *Contents) {
  1101. if (std::unique_ptr<RedirectingFileSystem::Entry> E =
  1102. parseEntry(&I, FS, /*IsRootEntry*/ false))
  1103. EntryArrayContents.push_back(std::move(E));
  1104. else
  1105. return nullptr;
  1106. }
  1107. } else if (Key == "external-contents") {
  1108. if (HasContents) {
  1109. error(I.getKey(),
  1110. "entry already has 'contents' or 'external-contents'");
  1111. return nullptr;
  1112. }
  1113. HasContents = true;
  1114. if (!parseScalarString(I.getValue(), Value, Buffer))
  1115. return nullptr;
  1116. SmallString<256> FullPath;
  1117. if (FS->IsRelativeOverlay) {
  1118. FullPath = FS->getExternalContentsPrefixDir();
  1119. assert(!FullPath.empty() &&
  1120. "External contents prefix directory must exist");
  1121. llvm::sys::path::append(FullPath, Value);
  1122. } else {
  1123. FullPath = Value;
  1124. }
  1125. if (FS->UseCanonicalizedPaths) {
  1126. // Guarantee that old YAML files containing paths with ".." and "."
  1127. // are properly canonicalized before read into the VFS.
  1128. FullPath = sys::path::remove_leading_dotslash(FullPath);
  1129. sys::path::remove_dots(FullPath, /*remove_dot_dot=*/true);
  1130. }
  1131. ExternalContentsPath = FullPath.str();
  1132. } else if (Key == "use-external-name") {
  1133. bool Val;
  1134. if (!parseScalarBool(I.getValue(), Val))
  1135. return nullptr;
  1136. UseExternalName =
  1137. Val ? RedirectingFileSystem::RedirectingFileEntry::NK_External
  1138. : RedirectingFileSystem::RedirectingFileEntry::NK_Virtual;
  1139. } else {
  1140. llvm_unreachable("key missing from Keys");
  1141. }
  1142. }
  1143. if (Stream.failed())
  1144. return nullptr;
  1145. // check for missing keys
  1146. if (!HasContents) {
  1147. error(N, "missing key 'contents' or 'external-contents'");
  1148. return nullptr;
  1149. }
  1150. if (!checkMissingKeys(N, Keys))
  1151. return nullptr;
  1152. // check invalid configuration
  1153. if (Kind == RedirectingFileSystem::EK_Directory &&
  1154. UseExternalName !=
  1155. RedirectingFileSystem::RedirectingFileEntry::NK_NotSet) {
  1156. error(N, "'use-external-name' is not supported for directories");
  1157. return nullptr;
  1158. }
  1159. if (IsRootEntry && !sys::path::is_absolute(Name)) {
  1160. assert(NameValueNode && "Name presence should be checked earlier");
  1161. error(NameValueNode,
  1162. "entry with relative path at the root level is not discoverable");
  1163. return nullptr;
  1164. }
  1165. // Remove trailing slash(es), being careful not to remove the root path
  1166. StringRef Trimmed(Name);
  1167. size_t RootPathLen = sys::path::root_path(Trimmed).size();
  1168. while (Trimmed.size() > RootPathLen &&
  1169. sys::path::is_separator(Trimmed.back()))
  1170. Trimmed = Trimmed.slice(0, Trimmed.size() - 1);
  1171. // Get the last component
  1172. StringRef LastComponent = sys::path::filename(Trimmed);
  1173. std::unique_ptr<RedirectingFileSystem::Entry> Result;
  1174. switch (Kind) {
  1175. case RedirectingFileSystem::EK_File:
  1176. Result = llvm::make_unique<RedirectingFileSystem::RedirectingFileEntry>(
  1177. LastComponent, std::move(ExternalContentsPath), UseExternalName);
  1178. break;
  1179. case RedirectingFileSystem::EK_Directory:
  1180. Result =
  1181. llvm::make_unique<RedirectingFileSystem::RedirectingDirectoryEntry>(
  1182. LastComponent, std::move(EntryArrayContents),
  1183. Status("", getNextVirtualUniqueID(),
  1184. std::chrono::system_clock::now(), 0, 0, 0,
  1185. file_type::directory_file, sys::fs::all_all));
  1186. break;
  1187. }
  1188. StringRef Parent = sys::path::parent_path(Trimmed);
  1189. if (Parent.empty())
  1190. return Result;
  1191. // if 'name' contains multiple components, create implicit directory entries
  1192. for (sys::path::reverse_iterator I = sys::path::rbegin(Parent),
  1193. E = sys::path::rend(Parent);
  1194. I != E; ++I) {
  1195. std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> Entries;
  1196. Entries.push_back(std::move(Result));
  1197. Result =
  1198. llvm::make_unique<RedirectingFileSystem::RedirectingDirectoryEntry>(
  1199. *I, std::move(Entries),
  1200. Status("", getNextVirtualUniqueID(),
  1201. std::chrono::system_clock::now(), 0, 0, 0,
  1202. file_type::directory_file, sys::fs::all_all));
  1203. }
  1204. return Result;
  1205. }
  1206. public:
  1207. RedirectingFileSystemParser(yaml::Stream &S) : Stream(S) {}
  1208. // false on error
  1209. bool parse(yaml::Node *Root, RedirectingFileSystem *FS) {
  1210. auto *Top = dyn_cast<yaml::MappingNode>(Root);
  1211. if (!Top) {
  1212. error(Root, "expected mapping node");
  1213. return false;
  1214. }
  1215. KeyStatusPair Fields[] = {
  1216. KeyStatusPair("version", true),
  1217. KeyStatusPair("case-sensitive", false),
  1218. KeyStatusPair("use-external-names", false),
  1219. KeyStatusPair("overlay-relative", false),
  1220. KeyStatusPair("fallthrough", false),
  1221. KeyStatusPair("roots", true),
  1222. };
  1223. DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields));
  1224. std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> RootEntries;
  1225. // Parse configuration and 'roots'
  1226. for (auto &I : *Top) {
  1227. SmallString<10> KeyBuffer;
  1228. StringRef Key;
  1229. if (!parseScalarString(I.getKey(), Key, KeyBuffer))
  1230. return false;
  1231. if (!checkDuplicateOrUnknownKey(I.getKey(), Key, Keys))
  1232. return false;
  1233. if (Key == "roots") {
  1234. auto *Roots = dyn_cast<yaml::SequenceNode>(I.getValue());
  1235. if (!Roots) {
  1236. error(I.getValue(), "expected array");
  1237. return false;
  1238. }
  1239. for (auto &I : *Roots) {
  1240. if (std::unique_ptr<RedirectingFileSystem::Entry> E =
  1241. parseEntry(&I, FS, /*IsRootEntry*/ true))
  1242. RootEntries.push_back(std::move(E));
  1243. else
  1244. return false;
  1245. }
  1246. } else if (Key == "version") {
  1247. StringRef VersionString;
  1248. SmallString<4> Storage;
  1249. if (!parseScalarString(I.getValue(), VersionString, Storage))
  1250. return false;
  1251. int Version;
  1252. if (VersionString.getAsInteger<int>(10, Version)) {
  1253. error(I.getValue(), "expected integer");
  1254. return false;
  1255. }
  1256. if (Version < 0) {
  1257. error(I.getValue(), "invalid version number");
  1258. return false;
  1259. }
  1260. if (Version != 0) {
  1261. error(I.getValue(), "version mismatch, expected 0");
  1262. return false;
  1263. }
  1264. } else if (Key == "case-sensitive") {
  1265. if (!parseScalarBool(I.getValue(), FS->CaseSensitive))
  1266. return false;
  1267. } else if (Key == "overlay-relative") {
  1268. if (!parseScalarBool(I.getValue(), FS->IsRelativeOverlay))
  1269. return false;
  1270. } else if (Key == "use-external-names") {
  1271. if (!parseScalarBool(I.getValue(), FS->UseExternalNames))
  1272. return false;
  1273. } else if (Key == "fallthrough") {
  1274. if (!parseScalarBool(I.getValue(), FS->IsFallthrough))
  1275. return false;
  1276. } else {
  1277. llvm_unreachable("key missing from Keys");
  1278. }
  1279. }
  1280. if (Stream.failed())
  1281. return false;
  1282. if (!checkMissingKeys(Top, Keys))
  1283. return false;
  1284. // Now that we sucessefully parsed the YAML file, canonicalize the internal
  1285. // representation to a proper directory tree so that we can search faster
  1286. // inside the VFS.
  1287. for (auto &E : RootEntries)
  1288. uniqueOverlayTree(FS, E.get());
  1289. return true;
  1290. }
  1291. };
  1292. RedirectingFileSystem *
  1293. RedirectingFileSystem::create(std::unique_ptr<MemoryBuffer> Buffer,
  1294. SourceMgr::DiagHandlerTy DiagHandler,
  1295. StringRef YAMLFilePath, void *DiagContext,
  1296. IntrusiveRefCntPtr<FileSystem> ExternalFS) {
  1297. SourceMgr SM;
  1298. yaml::Stream Stream(Buffer->getMemBufferRef(), SM);
  1299. SM.setDiagHandler(DiagHandler, DiagContext);
  1300. yaml::document_iterator DI = Stream.begin();
  1301. yaml::Node *Root = DI->getRoot();
  1302. if (DI == Stream.end() || !Root) {
  1303. SM.PrintMessage(SMLoc(), SourceMgr::DK_Error, "expected root node");
  1304. return nullptr;
  1305. }
  1306. RedirectingFileSystemParser P(Stream);
  1307. std::unique_ptr<RedirectingFileSystem> FS(
  1308. new RedirectingFileSystem(std::move(ExternalFS)));
  1309. if (!YAMLFilePath.empty()) {
  1310. // Use the YAML path from -ivfsoverlay to compute the dir to be prefixed
  1311. // to each 'external-contents' path.
  1312. //
  1313. // Example:
  1314. // -ivfsoverlay dummy.cache/vfs/vfs.yaml
  1315. // yields:
  1316. // FS->ExternalContentsPrefixDir => /<absolute_path_to>/dummy.cache/vfs
  1317. //
  1318. SmallString<256> OverlayAbsDir = sys::path::parent_path(YAMLFilePath);
  1319. std::error_code EC = llvm::sys::fs::make_absolute(OverlayAbsDir);
  1320. assert(!EC && "Overlay dir final path must be absolute");
  1321. (void)EC;
  1322. FS->setExternalContentsPrefixDir(OverlayAbsDir);
  1323. }
  1324. if (!P.parse(Root, FS.get()))
  1325. return nullptr;
  1326. return FS.release();
  1327. }
  1328. ErrorOr<RedirectingFileSystem::Entry *>
  1329. RedirectingFileSystem::lookupPath(const Twine &Path_) const {
  1330. SmallString<256> Path;
  1331. Path_.toVector(Path);
  1332. // Handle relative paths
  1333. if (std::error_code EC = makeAbsolute(Path))
  1334. return EC;
  1335. // Canonicalize path by removing ".", "..", "./", etc components. This is
  1336. // a VFS request, do bot bother about symlinks in the path components
  1337. // but canonicalize in order to perform the correct entry search.
  1338. if (UseCanonicalizedPaths) {
  1339. Path = sys::path::remove_leading_dotslash(Path);
  1340. sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
  1341. }
  1342. if (Path.empty())
  1343. return make_error_code(llvm::errc::invalid_argument);
  1344. sys::path::const_iterator Start = sys::path::begin(Path);
  1345. sys::path::const_iterator End = sys::path::end(Path);
  1346. for (const auto &Root : Roots) {
  1347. ErrorOr<RedirectingFileSystem::Entry *> Result =
  1348. lookupPath(Start, End, Root.get());
  1349. if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
  1350. return Result;
  1351. }
  1352. return make_error_code(llvm::errc::no_such_file_or_directory);
  1353. }
  1354. ErrorOr<RedirectingFileSystem::Entry *>
  1355. RedirectingFileSystem::lookupPath(sys::path::const_iterator Start,
  1356. sys::path::const_iterator End,
  1357. RedirectingFileSystem::Entry *From) const {
  1358. #ifndef _WIN32
  1359. assert(!isTraversalComponent(*Start) &&
  1360. !isTraversalComponent(From->getName()) &&
  1361. "Paths should not contain traversal components");
  1362. #else
  1363. // FIXME: this is here to support windows, remove it once canonicalized
  1364. // paths become globally default.
  1365. if (Start->equals("."))
  1366. ++Start;
  1367. #endif
  1368. StringRef FromName = From->getName();
  1369. // Forward the search to the next component in case this is an empty one.
  1370. if (!FromName.empty()) {
  1371. if (CaseSensitive ? !Start->equals(FromName)
  1372. : !Start->equals_lower(FromName))
  1373. // failure to match
  1374. return make_error_code(llvm::errc::no_such_file_or_directory);
  1375. ++Start;
  1376. if (Start == End) {
  1377. // Match!
  1378. return From;
  1379. }
  1380. }
  1381. auto *DE = dyn_cast<RedirectingFileSystem::RedirectingDirectoryEntry>(From);
  1382. if (!DE)
  1383. return make_error_code(llvm::errc::not_a_directory);
  1384. for (const std::unique_ptr<RedirectingFileSystem::Entry> &DirEntry :
  1385. llvm::make_range(DE->contents_begin(), DE->contents_end())) {
  1386. ErrorOr<RedirectingFileSystem::Entry *> Result =
  1387. lookupPath(Start, End, DirEntry.get());
  1388. if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
  1389. return Result;
  1390. }
  1391. return make_error_code(llvm::errc::no_such_file_or_directory);
  1392. }
  1393. static Status getRedirectedFileStatus(const Twine &Path, bool UseExternalNames,
  1394. Status ExternalStatus) {
  1395. Status S = ExternalStatus;
  1396. if (!UseExternalNames)
  1397. S = Status::copyWithNewName(S, Path.str());
  1398. S.IsVFSMapped = true;
  1399. return S;
  1400. }
  1401. ErrorOr<Status> RedirectingFileSystem::status(const Twine &Path,
  1402. RedirectingFileSystem::Entry *E) {
  1403. assert(E != nullptr);
  1404. if (auto *F = dyn_cast<RedirectingFileSystem::RedirectingFileEntry>(E)) {
  1405. ErrorOr<Status> S = ExternalFS->status(F->getExternalContentsPath());
  1406. assert(!S || S->getName() == F->getExternalContentsPath());
  1407. if (S)
  1408. return getRedirectedFileStatus(Path, F->useExternalName(UseExternalNames),
  1409. *S);
  1410. return S;
  1411. } else { // directory
  1412. auto *DE = cast<RedirectingFileSystem::RedirectingDirectoryEntry>(E);
  1413. return Status::copyWithNewName(DE->getStatus(), Path.str());
  1414. }
  1415. }
  1416. ErrorOr<Status> RedirectingFileSystem::status(const Twine &Path) {
  1417. ErrorOr<RedirectingFileSystem::Entry *> Result = lookupPath(Path);
  1418. if (!Result) {
  1419. if (IsFallthrough &&
  1420. Result.getError() == llvm::errc::no_such_file_or_directory) {
  1421. return ExternalFS->status(Path);
  1422. }
  1423. return Result.getError();
  1424. }
  1425. return status(Path, *Result);
  1426. }
  1427. namespace {
  1428. /// Provide a file wrapper with an overriden status.
  1429. class FileWithFixedStatus : public File {
  1430. std::unique_ptr<File> InnerFile;
  1431. Status S;
  1432. public:
  1433. FileWithFixedStatus(std::unique_ptr<File> InnerFile, Status S)
  1434. : InnerFile(std::move(InnerFile)), S(std::move(S)) {}
  1435. ErrorOr<Status> status() override { return S; }
  1436. ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
  1437. getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
  1438. bool IsVolatile) override {
  1439. return InnerFile->getBuffer(Name, FileSize, RequiresNullTerminator,
  1440. IsVolatile);
  1441. }
  1442. std::error_code close() override { return InnerFile->close(); }
  1443. };
  1444. } // namespace
  1445. ErrorOr<std::unique_ptr<File>>
  1446. RedirectingFileSystem::openFileForRead(const Twine &Path) {
  1447. ErrorOr<RedirectingFileSystem::Entry *> E = lookupPath(Path);
  1448. if (!E) {
  1449. if (IsFallthrough &&
  1450. E.getError() == llvm::errc::no_such_file_or_directory) {
  1451. return ExternalFS->openFileForRead(Path);
  1452. }
  1453. return E.getError();
  1454. }
  1455. auto *F = dyn_cast<RedirectingFileSystem::RedirectingFileEntry>(*E);
  1456. if (!F) // FIXME: errc::not_a_file?
  1457. return make_error_code(llvm::errc::invalid_argument);
  1458. auto Result = ExternalFS->openFileForRead(F->getExternalContentsPath());
  1459. if (!Result)
  1460. return Result;
  1461. auto ExternalStatus = (*Result)->status();
  1462. if (!ExternalStatus)
  1463. return ExternalStatus.getError();
  1464. // FIXME: Update the status with the name and VFSMapped.
  1465. Status S = getRedirectedFileStatus(Path, F->useExternalName(UseExternalNames),
  1466. *ExternalStatus);
  1467. return std::unique_ptr<File>(
  1468. llvm::make_unique<FileWithFixedStatus>(std::move(*Result), S));
  1469. }
  1470. std::error_code
  1471. RedirectingFileSystem::getRealPath(const Twine &Path,
  1472. SmallVectorImpl<char> &Output) const {
  1473. ErrorOr<RedirectingFileSystem::Entry *> Result = lookupPath(Path);
  1474. if (!Result) {
  1475. if (IsFallthrough &&
  1476. Result.getError() == llvm::errc::no_such_file_or_directory) {
  1477. return ExternalFS->getRealPath(Path, Output);
  1478. }
  1479. return Result.getError();
  1480. }
  1481. if (auto *F =
  1482. dyn_cast<RedirectingFileSystem::RedirectingFileEntry>(*Result)) {
  1483. return ExternalFS->getRealPath(F->getExternalContentsPath(), Output);
  1484. }
  1485. // Even if there is a directory entry, fall back to ExternalFS if allowed,
  1486. // because directories don't have a single external contents path.
  1487. return IsFallthrough ? ExternalFS->getRealPath(Path, Output)
  1488. : llvm::errc::invalid_argument;
  1489. }
  1490. IntrusiveRefCntPtr<FileSystem>
  1491. vfs::getVFSFromYAML(std::unique_ptr<MemoryBuffer> Buffer,
  1492. SourceMgr::DiagHandlerTy DiagHandler,
  1493. StringRef YAMLFilePath, void *DiagContext,
  1494. IntrusiveRefCntPtr<FileSystem> ExternalFS) {
  1495. return RedirectingFileSystem::create(std::move(Buffer), DiagHandler,
  1496. YAMLFilePath, DiagContext,
  1497. std::move(ExternalFS));
  1498. }
  1499. static void getVFSEntries(RedirectingFileSystem::Entry *SrcE,
  1500. SmallVectorImpl<StringRef> &Path,
  1501. SmallVectorImpl<YAMLVFSEntry> &Entries) {
  1502. auto Kind = SrcE->getKind();
  1503. if (Kind == RedirectingFileSystem::EK_Directory) {
  1504. auto *DE = dyn_cast<RedirectingFileSystem::RedirectingDirectoryEntry>(SrcE);
  1505. assert(DE && "Must be a directory");
  1506. for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
  1507. llvm::make_range(DE->contents_begin(), DE->contents_end())) {
  1508. Path.push_back(SubEntry->getName());
  1509. getVFSEntries(SubEntry.get(), Path, Entries);
  1510. Path.pop_back();
  1511. }
  1512. return;
  1513. }
  1514. assert(Kind == RedirectingFileSystem::EK_File && "Must be a EK_File");
  1515. auto *FE = dyn_cast<RedirectingFileSystem::RedirectingFileEntry>(SrcE);
  1516. assert(FE && "Must be a file");
  1517. SmallString<128> VPath;
  1518. for (auto &Comp : Path)
  1519. llvm::sys::path::append(VPath, Comp);
  1520. Entries.push_back(YAMLVFSEntry(VPath.c_str(), FE->getExternalContentsPath()));
  1521. }
  1522. void vfs::collectVFSFromYAML(std::unique_ptr<MemoryBuffer> Buffer,
  1523. SourceMgr::DiagHandlerTy DiagHandler,
  1524. StringRef YAMLFilePath,
  1525. SmallVectorImpl<YAMLVFSEntry> &CollectedEntries,
  1526. void *DiagContext,
  1527. IntrusiveRefCntPtr<FileSystem> ExternalFS) {
  1528. RedirectingFileSystem *VFS = RedirectingFileSystem::create(
  1529. std::move(Buffer), DiagHandler, YAMLFilePath, DiagContext,
  1530. std::move(ExternalFS));
  1531. ErrorOr<RedirectingFileSystem::Entry *> RootE = VFS->lookupPath("/");
  1532. if (!RootE)
  1533. return;
  1534. SmallVector<StringRef, 8> Components;
  1535. Components.push_back("/");
  1536. getVFSEntries(*RootE, Components, CollectedEntries);
  1537. }
  1538. UniqueID vfs::getNextVirtualUniqueID() {
  1539. static std::atomic<unsigned> UID;
  1540. unsigned ID = ++UID;
  1541. // The following assumes that uint64_t max will never collide with a real
  1542. // dev_t value from the OS.
  1543. return UniqueID(std::numeric_limits<uint64_t>::max(), ID);
  1544. }
  1545. void YAMLVFSWriter::addFileMapping(StringRef VirtualPath, StringRef RealPath) {
  1546. assert(sys::path::is_absolute(VirtualPath) && "virtual path not absolute");
  1547. assert(sys::path::is_absolute(RealPath) && "real path not absolute");
  1548. assert(!pathHasTraversal(VirtualPath) && "path traversal is not supported");
  1549. Mappings.emplace_back(VirtualPath, RealPath);
  1550. }
  1551. namespace {
  1552. class JSONWriter {
  1553. llvm::raw_ostream &OS;
  1554. SmallVector<StringRef, 16> DirStack;
  1555. unsigned getDirIndent() { return 4 * DirStack.size(); }
  1556. unsigned getFileIndent() { return 4 * (DirStack.size() + 1); }
  1557. bool containedIn(StringRef Parent, StringRef Path);
  1558. StringRef containedPart(StringRef Parent, StringRef Path);
  1559. void startDirectory(StringRef Path);
  1560. void endDirectory();
  1561. void writeEntry(StringRef VPath, StringRef RPath);
  1562. public:
  1563. JSONWriter(llvm::raw_ostream &OS) : OS(OS) {}
  1564. void write(ArrayRef<YAMLVFSEntry> Entries, Optional<bool> UseExternalNames,
  1565. Optional<bool> IsCaseSensitive, Optional<bool> IsOverlayRelative,
  1566. StringRef OverlayDir);
  1567. };
  1568. } // namespace
  1569. bool JSONWriter::containedIn(StringRef Parent, StringRef Path) {
  1570. using namespace llvm::sys;
  1571. // Compare each path component.
  1572. auto IParent = path::begin(Parent), EParent = path::end(Parent);
  1573. for (auto IChild = path::begin(Path), EChild = path::end(Path);
  1574. IParent != EParent && IChild != EChild; ++IParent, ++IChild) {
  1575. if (*IParent != *IChild)
  1576. return false;
  1577. }
  1578. // Have we exhausted the parent path?
  1579. return IParent == EParent;
  1580. }
  1581. StringRef JSONWriter::containedPart(StringRef Parent, StringRef Path) {
  1582. assert(!Parent.empty());
  1583. assert(containedIn(Parent, Path));
  1584. return Path.slice(Parent.size() + 1, StringRef::npos);
  1585. }
  1586. void JSONWriter::startDirectory(StringRef Path) {
  1587. StringRef Name =
  1588. DirStack.empty() ? Path : containedPart(DirStack.back(), Path);
  1589. DirStack.push_back(Path);
  1590. unsigned Indent = getDirIndent();
  1591. OS.indent(Indent) << "{\n";
  1592. OS.indent(Indent + 2) << "'type': 'directory',\n";
  1593. OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(Name) << "\",\n";
  1594. OS.indent(Indent + 2) << "'contents': [\n";
  1595. }
  1596. void JSONWriter::endDirectory() {
  1597. unsigned Indent = getDirIndent();
  1598. OS.indent(Indent + 2) << "]\n";
  1599. OS.indent(Indent) << "}";
  1600. DirStack.pop_back();
  1601. }
  1602. void JSONWriter::writeEntry(StringRef VPath, StringRef RPath) {
  1603. unsigned Indent = getFileIndent();
  1604. OS.indent(Indent) << "{\n";
  1605. OS.indent(Indent + 2) << "'type': 'file',\n";
  1606. OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(VPath) << "\",\n";
  1607. OS.indent(Indent + 2) << "'external-contents': \""
  1608. << llvm::yaml::escape(RPath) << "\"\n";
  1609. OS.indent(Indent) << "}";
  1610. }
  1611. void JSONWriter::write(ArrayRef<YAMLVFSEntry> Entries,
  1612. Optional<bool> UseExternalNames,
  1613. Optional<bool> IsCaseSensitive,
  1614. Optional<bool> IsOverlayRelative,
  1615. StringRef OverlayDir) {
  1616. using namespace llvm::sys;
  1617. OS << "{\n"
  1618. " 'version': 0,\n";
  1619. if (IsCaseSensitive.hasValue())
  1620. OS << " 'case-sensitive': '"
  1621. << (IsCaseSensitive.getValue() ? "true" : "false") << "',\n";
  1622. if (UseExternalNames.hasValue())
  1623. OS << " 'use-external-names': '"
  1624. << (UseExternalNames.getValue() ? "true" : "false") << "',\n";
  1625. bool UseOverlayRelative = false;
  1626. if (IsOverlayRelative.hasValue()) {
  1627. UseOverlayRelative = IsOverlayRelative.getValue();
  1628. OS << " 'overlay-relative': '" << (UseOverlayRelative ? "true" : "false")
  1629. << "',\n";
  1630. }
  1631. OS << " 'roots': [\n";
  1632. if (!Entries.empty()) {
  1633. const YAMLVFSEntry &Entry = Entries.front();
  1634. startDirectory(path::parent_path(Entry.VPath));
  1635. StringRef RPath = Entry.RPath;
  1636. if (UseOverlayRelative) {
  1637. unsigned OverlayDirLen = OverlayDir.size();
  1638. assert(RPath.substr(0, OverlayDirLen) == OverlayDir &&
  1639. "Overlay dir must be contained in RPath");
  1640. RPath = RPath.slice(OverlayDirLen, RPath.size());
  1641. }
  1642. writeEntry(path::filename(Entry.VPath), RPath);
  1643. for (const auto &Entry : Entries.slice(1)) {
  1644. StringRef Dir = path::parent_path(Entry.VPath);
  1645. if (Dir == DirStack.back())
  1646. OS << ",\n";
  1647. else {
  1648. while (!DirStack.empty() && !containedIn(DirStack.back(), Dir)) {
  1649. OS << "\n";
  1650. endDirectory();
  1651. }
  1652. OS << ",\n";
  1653. startDirectory(Dir);
  1654. }
  1655. StringRef RPath = Entry.RPath;
  1656. if (UseOverlayRelative) {
  1657. unsigned OverlayDirLen = OverlayDir.size();
  1658. assert(RPath.substr(0, OverlayDirLen) == OverlayDir &&
  1659. "Overlay dir must be contained in RPath");
  1660. RPath = RPath.slice(OverlayDirLen, RPath.size());
  1661. }
  1662. writeEntry(path::filename(Entry.VPath), RPath);
  1663. }
  1664. while (!DirStack.empty()) {
  1665. OS << "\n";
  1666. endDirectory();
  1667. }
  1668. OS << "\n";
  1669. }
  1670. OS << " ]\n"
  1671. << "}\n";
  1672. }
  1673. void YAMLVFSWriter::write(llvm::raw_ostream &OS) {
  1674. llvm::sort(Mappings, [](const YAMLVFSEntry &LHS, const YAMLVFSEntry &RHS) {
  1675. return LHS.VPath < RHS.VPath;
  1676. });
  1677. JSONWriter(OS).write(Mappings, UseExternalNames, IsCaseSensitive,
  1678. IsOverlayRelative, OverlayDir);
  1679. }
  1680. VFSFromYamlDirIterImpl::VFSFromYamlDirIterImpl(
  1681. const Twine &_Path,
  1682. RedirectingFileSystem::RedirectingDirectoryEntry::iterator Begin,
  1683. RedirectingFileSystem::RedirectingDirectoryEntry::iterator End,
  1684. bool IterateExternalFS, FileSystem &ExternalFS, std::error_code &EC)
  1685. : Dir(_Path.str()), Current(Begin), End(End),
  1686. IterateExternalFS(IterateExternalFS), ExternalFS(ExternalFS) {
  1687. EC = incrementImpl(/*IsFirstTime=*/true);
  1688. }
  1689. std::error_code VFSFromYamlDirIterImpl::increment() {
  1690. return incrementImpl(/*IsFirstTime=*/false);
  1691. }
  1692. std::error_code VFSFromYamlDirIterImpl::incrementExternal() {
  1693. assert(!(IsExternalFSCurrent && ExternalDirIter == directory_iterator()) &&
  1694. "incrementing past end");
  1695. std::error_code EC;
  1696. if (IsExternalFSCurrent) {
  1697. ExternalDirIter.increment(EC);
  1698. } else if (IterateExternalFS) {
  1699. ExternalDirIter = ExternalFS.dir_begin(Dir, EC);
  1700. IsExternalFSCurrent = true;
  1701. if (EC && EC != errc::no_such_file_or_directory)
  1702. return EC;
  1703. EC = {};
  1704. }
  1705. if (EC || ExternalDirIter == directory_iterator()) {
  1706. CurrentEntry = directory_entry();
  1707. } else {
  1708. CurrentEntry = *ExternalDirIter;
  1709. }
  1710. return EC;
  1711. }
  1712. std::error_code VFSFromYamlDirIterImpl::incrementContent(bool IsFirstTime) {
  1713. assert((IsFirstTime || Current != End) && "cannot iterate past end");
  1714. if (!IsFirstTime)
  1715. ++Current;
  1716. while (Current != End) {
  1717. SmallString<128> PathStr(Dir);
  1718. llvm::sys::path::append(PathStr, (*Current)->getName());
  1719. sys::fs::file_type Type;
  1720. switch ((*Current)->getKind()) {
  1721. case RedirectingFileSystem::EK_Directory:
  1722. Type = sys::fs::file_type::directory_file;
  1723. break;
  1724. case RedirectingFileSystem::EK_File:
  1725. Type = sys::fs::file_type::regular_file;
  1726. break;
  1727. }
  1728. CurrentEntry = directory_entry(PathStr.str(), Type);
  1729. return {};
  1730. }
  1731. return incrementExternal();
  1732. }
  1733. std::error_code VFSFromYamlDirIterImpl::incrementImpl(bool IsFirstTime) {
  1734. while (true) {
  1735. std::error_code EC = IsExternalFSCurrent ? incrementExternal()
  1736. : incrementContent(IsFirstTime);
  1737. if (EC || CurrentEntry.path().empty())
  1738. return EC;
  1739. StringRef Name = llvm::sys::path::filename(CurrentEntry.path());
  1740. if (SeenNames.insert(Name).second)
  1741. return EC; // name not seen before
  1742. }
  1743. llvm_unreachable("returned above");
  1744. }
  1745. vfs::recursive_directory_iterator::recursive_directory_iterator(
  1746. FileSystem &FS_, const Twine &Path, std::error_code &EC)
  1747. : FS(&FS_) {
  1748. directory_iterator I = FS->dir_begin(Path, EC);
  1749. if (I != directory_iterator()) {
  1750. State = std::make_shared<detail::RecDirIterState>();
  1751. State->Stack.push(I);
  1752. }
  1753. }
  1754. vfs::recursive_directory_iterator &
  1755. recursive_directory_iterator::increment(std::error_code &EC) {
  1756. assert(FS && State && !State->Stack.empty() && "incrementing past end");
  1757. assert(!State->Stack.top()->path().empty() && "non-canonical end iterator");
  1758. vfs::directory_iterator End;
  1759. if (State->HasNoPushRequest)
  1760. State->HasNoPushRequest = false;
  1761. else {
  1762. if (State->Stack.top()->type() == sys::fs::file_type::directory_file) {
  1763. vfs::directory_iterator I = FS->dir_begin(State->Stack.top()->path(), EC);
  1764. if (I != End) {
  1765. State->Stack.push(I);
  1766. return *this;
  1767. }
  1768. }
  1769. }
  1770. while (!State->Stack.empty() && State->Stack.top().increment(EC) == End)
  1771. State->Stack.pop();
  1772. if (State->Stack.empty())
  1773. State.reset(); // end iterator
  1774. return *this;
  1775. }