VirtualFileSystem.cpp 87 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586
  1. //===- VirtualFileSystem.cpp - Virtual File System Layer ------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This file implements the VirtualFileSystem interface.
  10. //
  11. //===----------------------------------------------------------------------===//
  12. #include "llvm/Support/VirtualFileSystem.h"
  13. #include "llvm/ADT/ArrayRef.h"
  14. #include "llvm/ADT/DenseMap.h"
  15. #include "llvm/ADT/IntrusiveRefCntPtr.h"
  16. #include "llvm/ADT/None.h"
  17. #include "llvm/ADT/Optional.h"
  18. #include "llvm/ADT/STLExtras.h"
  19. #include "llvm/ADT/SmallString.h"
  20. #include "llvm/ADT/SmallVector.h"
  21. #include "llvm/ADT/StringRef.h"
  22. #include "llvm/ADT/StringSet.h"
  23. #include "llvm/ADT/Twine.h"
  24. #include "llvm/ADT/iterator_range.h"
  25. #include "llvm/Config/llvm-config.h"
  26. #include "llvm/Support/Casting.h"
  27. #include "llvm/Support/Chrono.h"
  28. #include "llvm/Support/Compiler.h"
  29. #include "llvm/Support/Debug.h"
  30. #include "llvm/Support/Errc.h"
  31. #include "llvm/Support/ErrorHandling.h"
  32. #include "llvm/Support/ErrorOr.h"
  33. #include "llvm/Support/FileSystem.h"
  34. #include "llvm/Support/FileSystem/UniqueID.h"
  35. #include "llvm/Support/MemoryBuffer.h"
  36. #include "llvm/Support/Path.h"
  37. #include "llvm/Support/SMLoc.h"
  38. #include "llvm/Support/SourceMgr.h"
  39. #include "llvm/Support/YAMLParser.h"
  40. #include "llvm/Support/raw_ostream.h"
  41. #include <algorithm>
  42. #include <atomic>
  43. #include <cassert>
  44. #include <cstdint>
  45. #include <iterator>
  46. #include <limits>
  47. #include <memory>
  48. #include <string>
  49. #include <system_error>
  50. #include <utility>
  51. #include <vector>
  52. using namespace llvm;
  53. using namespace llvm::vfs;
  54. using llvm::sys::fs::file_t;
  55. using llvm::sys::fs::file_status;
  56. using llvm::sys::fs::file_type;
  57. using llvm::sys::fs::kInvalidFile;
  58. using llvm::sys::fs::perms;
  59. using llvm::sys::fs::UniqueID;
  60. Status::Status(const file_status &Status)
  61. : UID(Status.getUniqueID()), MTime(Status.getLastModificationTime()),
  62. User(Status.getUser()), Group(Status.getGroup()), Size(Status.getSize()),
  63. Type(Status.type()), Perms(Status.permissions()) {}
  64. Status::Status(const Twine &Name, UniqueID UID, sys::TimePoint<> MTime,
  65. uint32_t User, uint32_t Group, uint64_t Size, file_type Type,
  66. perms Perms)
  67. : Name(Name.str()), UID(UID), MTime(MTime), User(User), Group(Group),
  68. Size(Size), Type(Type), Perms(Perms) {}
  69. Status Status::copyWithNewSize(const Status &In, uint64_t NewSize) {
  70. return Status(In.getName(), In.getUniqueID(), In.getLastModificationTime(),
  71. In.getUser(), In.getGroup(), NewSize, In.getType(),
  72. In.getPermissions());
  73. }
  74. Status Status::copyWithNewName(const Status &In, const Twine &NewName) {
  75. return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),
  76. In.getUser(), In.getGroup(), In.getSize(), In.getType(),
  77. In.getPermissions());
  78. }
  79. Status Status::copyWithNewName(const file_status &In, const Twine &NewName) {
  80. return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),
  81. In.getUser(), In.getGroup(), In.getSize(), In.type(),
  82. In.permissions());
  83. }
  84. bool Status::equivalent(const Status &Other) const {
  85. assert(isStatusKnown() && Other.isStatusKnown());
  86. return getUniqueID() == Other.getUniqueID();
  87. }
  88. bool Status::isDirectory() const { return Type == file_type::directory_file; }
  89. bool Status::isRegularFile() const { return Type == file_type::regular_file; }
  90. bool Status::isOther() const {
  91. return exists() && !isRegularFile() && !isDirectory() && !isSymlink();
  92. }
  93. bool Status::isSymlink() const { return Type == file_type::symlink_file; }
  94. bool Status::isStatusKnown() const { return Type != file_type::status_error; }
  95. bool Status::exists() const {
  96. return isStatusKnown() && Type != file_type::file_not_found;
  97. }
  98. File::~File() = default;
  99. FileSystem::~FileSystem() = default;
  100. ErrorOr<std::unique_ptr<MemoryBuffer>>
  101. FileSystem::getBufferForFile(const llvm::Twine &Name, int64_t FileSize,
  102. bool RequiresNullTerminator, bool IsVolatile) {
  103. auto F = openFileForRead(Name);
  104. if (!F)
  105. return F.getError();
  106. return (*F)->getBuffer(Name, FileSize, RequiresNullTerminator, IsVolatile);
  107. }
  108. std::error_code FileSystem::makeAbsolute(SmallVectorImpl<char> &Path) const {
  109. if (llvm::sys::path::is_absolute(Path))
  110. return {};
  111. auto WorkingDir = getCurrentWorkingDirectory();
  112. if (!WorkingDir)
  113. return WorkingDir.getError();
  114. llvm::sys::fs::make_absolute(WorkingDir.get(), Path);
  115. return {};
  116. }
  117. std::error_code FileSystem::getRealPath(const Twine &Path,
  118. SmallVectorImpl<char> &Output) const {
  119. return errc::operation_not_permitted;
  120. }
  121. std::error_code FileSystem::isLocal(const Twine &Path, bool &Result) {
  122. return errc::operation_not_permitted;
  123. }
  124. bool FileSystem::exists(const Twine &Path) {
  125. auto Status = status(Path);
  126. return Status && Status->exists();
  127. }
  128. #ifndef NDEBUG
  129. static bool isTraversalComponent(StringRef Component) {
  130. return Component.equals("..") || Component.equals(".");
  131. }
  132. static bool pathHasTraversal(StringRef Path) {
  133. using namespace llvm::sys;
  134. for (StringRef Comp : llvm::make_range(path::begin(Path), path::end(Path)))
  135. if (isTraversalComponent(Comp))
  136. return true;
  137. return false;
  138. }
  139. #endif
  140. //===-----------------------------------------------------------------------===/
  141. // RealFileSystem implementation
  142. //===-----------------------------------------------------------------------===/
  143. namespace {
  144. /// Wrapper around a raw file descriptor.
  145. class RealFile : public File {
  146. friend class RealFileSystem;
  147. file_t FD;
  148. Status S;
  149. std::string RealName;
  150. RealFile(file_t RawFD, StringRef NewName, StringRef NewRealPathName)
  151. : FD(RawFD), S(NewName, {}, {}, {}, {}, {},
  152. llvm::sys::fs::file_type::status_error, {}),
  153. RealName(NewRealPathName.str()) {
  154. assert(FD != kInvalidFile && "Invalid or inactive file descriptor");
  155. }
  156. public:
  157. ~RealFile() override;
  158. ErrorOr<Status> status() override;
  159. ErrorOr<std::string> getName() override;
  160. ErrorOr<std::unique_ptr<MemoryBuffer>> getBuffer(const Twine &Name,
  161. int64_t FileSize,
  162. bool RequiresNullTerminator,
  163. bool IsVolatile) override;
  164. std::error_code close() override;
  165. void setPath(const Twine &Path) override;
  166. };
  167. } // namespace
  168. RealFile::~RealFile() { close(); }
  169. ErrorOr<Status> RealFile::status() {
  170. assert(FD != kInvalidFile && "cannot stat closed file");
  171. if (!S.isStatusKnown()) {
  172. file_status RealStatus;
  173. if (std::error_code EC = sys::fs::status(FD, RealStatus))
  174. return EC;
  175. S = Status::copyWithNewName(RealStatus, S.getName());
  176. }
  177. return S;
  178. }
  179. ErrorOr<std::string> RealFile::getName() {
  180. return RealName.empty() ? S.getName().str() : RealName;
  181. }
  182. ErrorOr<std::unique_ptr<MemoryBuffer>>
  183. RealFile::getBuffer(const Twine &Name, int64_t FileSize,
  184. bool RequiresNullTerminator, bool IsVolatile) {
  185. assert(FD != kInvalidFile && "cannot get buffer for closed file");
  186. return MemoryBuffer::getOpenFile(FD, Name, FileSize, RequiresNullTerminator,
  187. IsVolatile);
  188. }
  189. std::error_code RealFile::close() {
  190. std::error_code EC = sys::fs::closeFile(FD);
  191. FD = kInvalidFile;
  192. return EC;
  193. }
  194. void RealFile::setPath(const Twine &Path) {
  195. RealName = Path.str();
  196. if (auto Status = status())
  197. S = Status.get().copyWithNewName(Status.get(), Path);
  198. }
  199. namespace {
  200. /// A file system according to your operating system.
  201. /// This may be linked to the process's working directory, or maintain its own.
  202. ///
  203. /// Currently, its own working directory is emulated by storing the path and
  204. /// sending absolute paths to llvm::sys::fs:: functions.
  205. /// A more principled approach would be to push this down a level, modelling
  206. /// the working dir as an llvm::sys::fs::WorkingDir or similar.
  207. /// This would enable the use of openat()-style functions on some platforms.
  208. class RealFileSystem : public FileSystem {
  209. public:
  210. explicit RealFileSystem(bool LinkCWDToProcess) {
  211. if (!LinkCWDToProcess) {
  212. SmallString<128> PWD, RealPWD;
  213. if (llvm::sys::fs::current_path(PWD))
  214. return; // Awful, but nothing to do here.
  215. if (llvm::sys::fs::real_path(PWD, RealPWD))
  216. WD = {PWD, PWD};
  217. else
  218. WD = {PWD, RealPWD};
  219. }
  220. }
  221. ErrorOr<Status> status(const Twine &Path) override;
  222. ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override;
  223. directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
  224. llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override;
  225. std::error_code setCurrentWorkingDirectory(const Twine &Path) override;
  226. std::error_code isLocal(const Twine &Path, bool &Result) override;
  227. std::error_code getRealPath(const Twine &Path,
  228. SmallVectorImpl<char> &Output) const override;
  229. private:
  230. // If this FS has its own working dir, use it to make Path absolute.
  231. // The returned twine is safe to use as long as both Storage and Path live.
  232. Twine adjustPath(const Twine &Path, SmallVectorImpl<char> &Storage) const {
  233. if (!WD)
  234. return Path;
  235. Path.toVector(Storage);
  236. sys::fs::make_absolute(WD->Resolved, Storage);
  237. return Storage;
  238. }
  239. struct WorkingDirectory {
  240. // The current working directory, without symlinks resolved. (echo $PWD).
  241. SmallString<128> Specified;
  242. // The current working directory, with links resolved. (readlink .).
  243. SmallString<128> Resolved;
  244. };
  245. Optional<WorkingDirectory> WD;
  246. };
  247. } // namespace
  248. ErrorOr<Status> RealFileSystem::status(const Twine &Path) {
  249. SmallString<256> Storage;
  250. sys::fs::file_status RealStatus;
  251. if (std::error_code EC =
  252. sys::fs::status(adjustPath(Path, Storage), RealStatus))
  253. return EC;
  254. return Status::copyWithNewName(RealStatus, Path);
  255. }
  256. ErrorOr<std::unique_ptr<File>>
  257. RealFileSystem::openFileForRead(const Twine &Name) {
  258. SmallString<256> RealName, Storage;
  259. Expected<file_t> FDOrErr = sys::fs::openNativeFileForRead(
  260. adjustPath(Name, Storage), sys::fs::OF_None, &RealName);
  261. if (!FDOrErr)
  262. return errorToErrorCode(FDOrErr.takeError());
  263. return std::unique_ptr<File>(
  264. new RealFile(*FDOrErr, Name.str(), RealName.str()));
  265. }
  266. llvm::ErrorOr<std::string> RealFileSystem::getCurrentWorkingDirectory() const {
  267. if (WD)
  268. return std::string(WD->Specified.str());
  269. SmallString<128> Dir;
  270. if (std::error_code EC = llvm::sys::fs::current_path(Dir))
  271. return EC;
  272. return std::string(Dir.str());
  273. }
  274. std::error_code RealFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
  275. if (!WD)
  276. return llvm::sys::fs::set_current_path(Path);
  277. SmallString<128> Absolute, Resolved, Storage;
  278. adjustPath(Path, Storage).toVector(Absolute);
  279. bool IsDir;
  280. if (auto Err = llvm::sys::fs::is_directory(Absolute, IsDir))
  281. return Err;
  282. if (!IsDir)
  283. return std::make_error_code(std::errc::not_a_directory);
  284. if (auto Err = llvm::sys::fs::real_path(Absolute, Resolved))
  285. return Err;
  286. WD = {Absolute, Resolved};
  287. return std::error_code();
  288. }
  289. std::error_code RealFileSystem::isLocal(const Twine &Path, bool &Result) {
  290. SmallString<256> Storage;
  291. return llvm::sys::fs::is_local(adjustPath(Path, Storage), Result);
  292. }
  293. std::error_code
  294. RealFileSystem::getRealPath(const Twine &Path,
  295. SmallVectorImpl<char> &Output) const {
  296. SmallString<256> Storage;
  297. return llvm::sys::fs::real_path(adjustPath(Path, Storage), Output);
  298. }
  299. IntrusiveRefCntPtr<FileSystem> vfs::getRealFileSystem() {
  300. static IntrusiveRefCntPtr<FileSystem> FS(new RealFileSystem(true));
  301. return FS;
  302. }
  303. std::unique_ptr<FileSystem> vfs::createPhysicalFileSystem() {
  304. return std::make_unique<RealFileSystem>(false);
  305. }
  306. namespace {
  307. class RealFSDirIter : public llvm::vfs::detail::DirIterImpl {
  308. llvm::sys::fs::directory_iterator Iter;
  309. public:
  310. RealFSDirIter(const Twine &Path, std::error_code &EC) : Iter(Path, EC) {
  311. if (Iter != llvm::sys::fs::directory_iterator())
  312. CurrentEntry = directory_entry(Iter->path(), Iter->type());
  313. }
  314. std::error_code increment() override {
  315. std::error_code EC;
  316. Iter.increment(EC);
  317. CurrentEntry = (Iter == llvm::sys::fs::directory_iterator())
  318. ? directory_entry()
  319. : directory_entry(Iter->path(), Iter->type());
  320. return EC;
  321. }
  322. };
  323. } // namespace
  324. directory_iterator RealFileSystem::dir_begin(const Twine &Dir,
  325. std::error_code &EC) {
  326. SmallString<128> Storage;
  327. return directory_iterator(
  328. std::make_shared<RealFSDirIter>(adjustPath(Dir, Storage), EC));
  329. }
  330. //===-----------------------------------------------------------------------===/
  331. // OverlayFileSystem implementation
  332. //===-----------------------------------------------------------------------===/
  333. OverlayFileSystem::OverlayFileSystem(IntrusiveRefCntPtr<FileSystem> BaseFS) {
  334. FSList.push_back(std::move(BaseFS));
  335. }
  336. void OverlayFileSystem::pushOverlay(IntrusiveRefCntPtr<FileSystem> FS) {
  337. FSList.push_back(FS);
  338. // Synchronize added file systems by duplicating the working directory from
  339. // the first one in the list.
  340. FS->setCurrentWorkingDirectory(getCurrentWorkingDirectory().get());
  341. }
  342. ErrorOr<Status> OverlayFileSystem::status(const Twine &Path) {
  343. // FIXME: handle symlinks that cross file systems
  344. for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) {
  345. ErrorOr<Status> Status = (*I)->status(Path);
  346. if (Status || Status.getError() != llvm::errc::no_such_file_or_directory)
  347. return Status;
  348. }
  349. return make_error_code(llvm::errc::no_such_file_or_directory);
  350. }
  351. ErrorOr<std::unique_ptr<File>>
  352. OverlayFileSystem::openFileForRead(const llvm::Twine &Path) {
  353. // FIXME: handle symlinks that cross file systems
  354. for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) {
  355. auto Result = (*I)->openFileForRead(Path);
  356. if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
  357. return Result;
  358. }
  359. return make_error_code(llvm::errc::no_such_file_or_directory);
  360. }
  361. llvm::ErrorOr<std::string>
  362. OverlayFileSystem::getCurrentWorkingDirectory() const {
  363. // All file systems are synchronized, just take the first working directory.
  364. return FSList.front()->getCurrentWorkingDirectory();
  365. }
  366. std::error_code
  367. OverlayFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
  368. for (auto &FS : FSList)
  369. if (std::error_code EC = FS->setCurrentWorkingDirectory(Path))
  370. return EC;
  371. return {};
  372. }
  373. std::error_code OverlayFileSystem::isLocal(const Twine &Path, bool &Result) {
  374. for (auto &FS : FSList)
  375. if (FS->exists(Path))
  376. return FS->isLocal(Path, Result);
  377. return errc::no_such_file_or_directory;
  378. }
  379. std::error_code
  380. OverlayFileSystem::getRealPath(const Twine &Path,
  381. SmallVectorImpl<char> &Output) const {
  382. for (const auto &FS : FSList)
  383. if (FS->exists(Path))
  384. return FS->getRealPath(Path, Output);
  385. return errc::no_such_file_or_directory;
  386. }
  387. llvm::vfs::detail::DirIterImpl::~DirIterImpl() = default;
  388. namespace {
  389. /// Combines and deduplicates directory entries across multiple file systems.
  390. class CombiningDirIterImpl : public llvm::vfs::detail::DirIterImpl {
  391. using FileSystemPtr = llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>;
  392. /// File systems to check for entries in. Processed in reverse order.
  393. SmallVector<FileSystemPtr, 8> FSList;
  394. /// The directory iterator for the current filesystem.
  395. directory_iterator CurrentDirIter;
  396. /// The path of the directory to iterate the entries of.
  397. std::string DirPath;
  398. /// The set of names already returned as entries.
  399. llvm::StringSet<> SeenNames;
  400. /// Sets \c CurrentDirIter to an iterator of \c DirPath in the next file
  401. /// system in the list, or leaves it as is (at its end position) if we've
  402. /// already gone through them all.
  403. std::error_code incrementFS() {
  404. while (!FSList.empty()) {
  405. std::error_code EC;
  406. CurrentDirIter = FSList.back()->dir_begin(DirPath, EC);
  407. FSList.pop_back();
  408. if (EC && EC != errc::no_such_file_or_directory)
  409. return EC;
  410. if (CurrentDirIter != directory_iterator())
  411. break; // found
  412. }
  413. return {};
  414. }
  415. std::error_code incrementDirIter(bool IsFirstTime) {
  416. assert((IsFirstTime || CurrentDirIter != directory_iterator()) &&
  417. "incrementing past end");
  418. std::error_code EC;
  419. if (!IsFirstTime)
  420. CurrentDirIter.increment(EC);
  421. if (!EC && CurrentDirIter == directory_iterator())
  422. EC = incrementFS();
  423. return EC;
  424. }
  425. std::error_code incrementImpl(bool IsFirstTime) {
  426. while (true) {
  427. std::error_code EC = incrementDirIter(IsFirstTime);
  428. if (EC || CurrentDirIter == directory_iterator()) {
  429. CurrentEntry = directory_entry();
  430. return EC;
  431. }
  432. CurrentEntry = *CurrentDirIter;
  433. StringRef Name = llvm::sys::path::filename(CurrentEntry.path());
  434. if (SeenNames.insert(Name).second)
  435. return EC; // name not seen before
  436. }
  437. llvm_unreachable("returned above");
  438. }
  439. public:
  440. CombiningDirIterImpl(ArrayRef<FileSystemPtr> FileSystems, std::string Dir,
  441. std::error_code &EC)
  442. : FSList(FileSystems.begin(), FileSystems.end()),
  443. DirPath(std::move(Dir)) {
  444. if (!FSList.empty()) {
  445. CurrentDirIter = FSList.back()->dir_begin(DirPath, EC);
  446. FSList.pop_back();
  447. if (!EC || EC == errc::no_such_file_or_directory)
  448. EC = incrementImpl(true);
  449. }
  450. }
  451. CombiningDirIterImpl(directory_iterator FirstIter, FileSystemPtr Fallback,
  452. std::string FallbackDir, std::error_code &EC)
  453. : FSList({Fallback}), CurrentDirIter(FirstIter),
  454. DirPath(std::move(FallbackDir)) {
  455. if (!EC || EC == errc::no_such_file_or_directory)
  456. EC = incrementImpl(true);
  457. }
  458. std::error_code increment() override { return incrementImpl(false); }
  459. };
  460. } // namespace
  461. directory_iterator OverlayFileSystem::dir_begin(const Twine &Dir,
  462. std::error_code &EC) {
  463. return directory_iterator(
  464. std::make_shared<CombiningDirIterImpl>(FSList, Dir.str(), EC));
  465. }
  466. void ProxyFileSystem::anchor() {}
  467. //===-----------------------------------------------------------------------===/
  468. // CaseInsensitiveFileSystem implementation
  469. //===-----------------------------------------------------------------------===/
  470. bool CaseInsensitiveFileSystem::exclude(StringRef Dir, StringRef File) {
  471. if (!Maps.count(Dir)) {
  472. // We have no map for this Dir, but see if we can exclude the file by
  473. // excluding Dir from its parent.
  474. StringRef Parent = llvm::sys::path::parent_path(Dir);
  475. if (!Parent.empty() &&
  476. exclude(Parent, llvm::sys::path::filename(Dir))) {
  477. return true;
  478. }
  479. return false;
  480. }
  481. return !Maps[Dir].count(File.lower());
  482. }
  483. std::error_code CaseInsensitiveFileSystem::findCaseInsensitivePath(
  484. StringRef Path, SmallVectorImpl<char> &FoundPath) {
  485. StringRef FileName = llvm::sys::path::filename(Path);
  486. StringRef Dir = llvm::sys::path::parent_path(Path);
  487. if (Dir.empty())
  488. Dir = ".";
  489. if (exclude(Dir, FileName))
  490. return llvm::errc::no_such_file_or_directory;
  491. if (Maps.count(Dir)) {
  492. // If we have a map for this Dir and File wasn't excluded above, it must
  493. // exist.
  494. llvm::sys::path::append(FoundPath, Dir, Maps[Dir][FileName.lower()]);
  495. return std::error_code();
  496. }
  497. std::error_code EC;
  498. directory_iterator I = Base->dir_begin(Dir, EC);
  499. if (EC == errc::no_such_file_or_directory) {
  500. // If the dir doesn't exist, try to find it and try again.
  501. SmallVector<char, 512> NewDir;
  502. if (llvm::sys::path::parent_path(Dir).empty() ||
  503. (EC = findCaseInsensitivePath(Dir, NewDir))) {
  504. // Insert a dummy map value to mark the dir as non-existent.
  505. Maps.lookup(Dir);
  506. return EC;
  507. }
  508. llvm::sys::path::append(NewDir, FileName);
  509. return findCaseInsensitivePath(StringRef(NewDir.data(), NewDir.size()),
  510. FoundPath);
  511. }
  512. // These special entries always exist, but won't show up in the listing below.
  513. Maps[Dir]["."] = ".";
  514. Maps[Dir][".."] = "..";
  515. directory_iterator E;
  516. for (; I != E; I.increment(EC)) {
  517. StringRef DirEntry = llvm::sys::path::filename(I->path());
  518. Maps[Dir][DirEntry.lower()] = DirEntry.str();
  519. }
  520. if (EC) {
  521. // If there were problems, scrap the whole map as it may not be complete.
  522. Maps.erase(Dir);
  523. return EC;
  524. }
  525. auto MI = Maps[Dir].find(FileName.lower());
  526. if (MI != Maps[Dir].end()) {
  527. llvm::sys::path::append(FoundPath, Dir, MI->second);
  528. return std::error_code();
  529. }
  530. return llvm::errc::no_such_file_or_directory;
  531. }
  532. llvm::ErrorOr<Status> CaseInsensitiveFileSystem::status(const Twine &Path) {
  533. SmallVector<char, 512> NewPath;
  534. if (std::error_code EC = findCaseInsensitivePath(Path.str(), NewPath))
  535. return EC;
  536. return Base->status(NewPath);
  537. }
  538. llvm::ErrorOr<std::unique_ptr<File>>
  539. CaseInsensitiveFileSystem::openFileForRead(const Twine &Path) {
  540. SmallVector<char, 512> NewPath;
  541. if (std::error_code EC = findCaseInsensitivePath(Path.str(), NewPath))
  542. return EC;
  543. return Base->openFileForRead(NewPath);
  544. }
  545. directory_iterator CaseInsensitiveFileSystem::dir_begin(const Twine &Path,
  546. std::error_code &EC) {
  547. SmallVector<char, 512> NewPath;
  548. if ((EC = findCaseInsensitivePath(Path.str(), NewPath)))
  549. return directory_iterator();
  550. return Base->dir_begin(NewPath, EC);
  551. }
  552. namespace llvm {
  553. namespace vfs {
  554. namespace detail {
  555. enum InMemoryNodeKind { IME_File, IME_Directory, IME_HardLink };
  556. /// The in memory file system is a tree of Nodes. Every node can either be a
  557. /// file , hardlink or a directory.
  558. class InMemoryNode {
  559. InMemoryNodeKind Kind;
  560. std::string FileName;
  561. public:
  562. InMemoryNode(llvm::StringRef FileName, InMemoryNodeKind Kind)
  563. : Kind(Kind), FileName(std::string(llvm::sys::path::filename(FileName))) {
  564. }
  565. virtual ~InMemoryNode() = default;
  566. /// Return the \p Status for this node. \p RequestedName should be the name
  567. /// through which the caller referred to this node. It will override
  568. /// \p Status::Name in the return value, to mimic the behavior of \p RealFile.
  569. virtual Status getStatus(const Twine &RequestedName) const = 0;
  570. /// Get the filename of this node (the name without the directory part).
  571. StringRef getFileName() const { return FileName; }
  572. InMemoryNodeKind getKind() const { return Kind; }
  573. virtual std::string toString(unsigned Indent) const = 0;
  574. };
  575. class InMemoryFile : public InMemoryNode {
  576. Status Stat;
  577. std::unique_ptr<llvm::MemoryBuffer> Buffer;
  578. public:
  579. InMemoryFile(Status Stat, std::unique_ptr<llvm::MemoryBuffer> Buffer)
  580. : InMemoryNode(Stat.getName(), IME_File), Stat(std::move(Stat)),
  581. Buffer(std::move(Buffer)) {}
  582. Status getStatus(const Twine &RequestedName) const override {
  583. return Status::copyWithNewName(Stat, RequestedName);
  584. }
  585. llvm::MemoryBuffer *getBuffer() const { return Buffer.get(); }
  586. std::string toString(unsigned Indent) const override {
  587. return (std::string(Indent, ' ') + Stat.getName() + "\n").str();
  588. }
  589. static bool classof(const InMemoryNode *N) {
  590. return N->getKind() == IME_File;
  591. }
  592. };
  593. namespace {
  594. class InMemoryHardLink : public InMemoryNode {
  595. const InMemoryFile &ResolvedFile;
  596. public:
  597. InMemoryHardLink(StringRef Path, const InMemoryFile &ResolvedFile)
  598. : InMemoryNode(Path, IME_HardLink), ResolvedFile(ResolvedFile) {}
  599. const InMemoryFile &getResolvedFile() const { return ResolvedFile; }
  600. Status getStatus(const Twine &RequestedName) const override {
  601. return ResolvedFile.getStatus(RequestedName);
  602. }
  603. std::string toString(unsigned Indent) const override {
  604. return std::string(Indent, ' ') + "HardLink to -> " +
  605. ResolvedFile.toString(0);
  606. }
  607. static bool classof(const InMemoryNode *N) {
  608. return N->getKind() == IME_HardLink;
  609. }
  610. };
  611. /// Adapt a InMemoryFile for VFS' File interface. The goal is to make
  612. /// \p InMemoryFileAdaptor mimic as much as possible the behavior of
  613. /// \p RealFile.
  614. class InMemoryFileAdaptor : public File {
  615. const InMemoryFile &Node;
  616. /// The name to use when returning a Status for this file.
  617. std::string RequestedName;
  618. public:
  619. explicit InMemoryFileAdaptor(const InMemoryFile &Node,
  620. std::string RequestedName)
  621. : Node(Node), RequestedName(std::move(RequestedName)) {}
  622. llvm::ErrorOr<Status> status() override {
  623. return Node.getStatus(RequestedName);
  624. }
  625. llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
  626. getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
  627. bool IsVolatile) override {
  628. llvm::MemoryBuffer *Buf = Node.getBuffer();
  629. return llvm::MemoryBuffer::getMemBuffer(
  630. Buf->getBuffer(), Buf->getBufferIdentifier(), RequiresNullTerminator);
  631. }
  632. std::error_code close() override { return {}; }
  633. void setPath(const Twine &Path) override { RequestedName = Path.str(); }
  634. };
  635. } // namespace
  636. class InMemoryDirectory : public InMemoryNode {
  637. Status Stat;
  638. llvm::StringMap<std::unique_ptr<InMemoryNode>> Entries;
  639. public:
  640. InMemoryDirectory(Status Stat)
  641. : InMemoryNode(Stat.getName(), IME_Directory), Stat(std::move(Stat)) {}
  642. /// Return the \p Status for this node. \p RequestedName should be the name
  643. /// through which the caller referred to this node. It will override
  644. /// \p Status::Name in the return value, to mimic the behavior of \p RealFile.
  645. Status getStatus(const Twine &RequestedName) const override {
  646. return Status::copyWithNewName(Stat, RequestedName);
  647. }
  648. UniqueID getUniqueID() const { return Stat.getUniqueID(); }
  649. InMemoryNode *getChild(StringRef Name) {
  650. auto I = Entries.find(Name);
  651. if (I != Entries.end())
  652. return I->second.get();
  653. return nullptr;
  654. }
  655. InMemoryNode *addChild(StringRef Name, std::unique_ptr<InMemoryNode> Child) {
  656. return Entries.insert(make_pair(Name, std::move(Child)))
  657. .first->second.get();
  658. }
  659. using const_iterator = decltype(Entries)::const_iterator;
  660. const_iterator begin() const { return Entries.begin(); }
  661. const_iterator end() const { return Entries.end(); }
  662. std::string toString(unsigned Indent) const override {
  663. std::string Result =
  664. (std::string(Indent, ' ') + Stat.getName() + "\n").str();
  665. for (const auto &Entry : Entries)
  666. Result += Entry.second->toString(Indent + 2);
  667. return Result;
  668. }
  669. static bool classof(const InMemoryNode *N) {
  670. return N->getKind() == IME_Directory;
  671. }
  672. };
  673. } // namespace detail
  674. // The UniqueID of in-memory files is derived from path and content.
  675. // This avoids difficulties in creating exactly equivalent in-memory FSes,
  676. // as often needed in multithreaded programs.
  677. static sys::fs::UniqueID getUniqueID(hash_code Hash) {
  678. return sys::fs::UniqueID(std::numeric_limits<uint64_t>::max(),
  679. uint64_t(size_t(Hash)));
  680. }
  681. static sys::fs::UniqueID getFileID(sys::fs::UniqueID Parent,
  682. llvm::StringRef Name,
  683. llvm::StringRef Contents) {
  684. return getUniqueID(llvm::hash_combine(Parent.getFile(), Name, Contents));
  685. }
  686. static sys::fs::UniqueID getDirectoryID(sys::fs::UniqueID Parent,
  687. llvm::StringRef Name) {
  688. return getUniqueID(llvm::hash_combine(Parent.getFile(), Name));
  689. }
  690. Status detail::NewInMemoryNodeInfo::makeStatus() const {
  691. UniqueID UID =
  692. (Type == sys::fs::file_type::directory_file)
  693. ? getDirectoryID(DirUID, Name)
  694. : getFileID(DirUID, Name, Buffer ? Buffer->getBuffer() : "");
  695. return Status(Path, UID, llvm::sys::toTimePoint(ModificationTime), User,
  696. Group, Buffer ? Buffer->getBufferSize() : 0, Type, Perms);
  697. }
  698. InMemoryFileSystem::InMemoryFileSystem(bool UseNormalizedPaths)
  699. : Root(new detail::InMemoryDirectory(
  700. Status("", getDirectoryID(llvm::sys::fs::UniqueID(), ""),
  701. llvm::sys::TimePoint<>(), 0, 0, 0,
  702. llvm::sys::fs::file_type::directory_file,
  703. llvm::sys::fs::perms::all_all))),
  704. UseNormalizedPaths(UseNormalizedPaths) {}
  705. InMemoryFileSystem::~InMemoryFileSystem() = default;
  706. std::string InMemoryFileSystem::toString() const {
  707. return Root->toString(/*Indent=*/0);
  708. }
  709. bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime,
  710. std::unique_ptr<llvm::MemoryBuffer> Buffer,
  711. Optional<uint32_t> User,
  712. Optional<uint32_t> Group,
  713. Optional<llvm::sys::fs::file_type> Type,
  714. Optional<llvm::sys::fs::perms> Perms,
  715. MakeNodeFn MakeNode) {
  716. SmallString<128> Path;
  717. P.toVector(Path);
  718. // Fix up relative paths. This just prepends the current working directory.
  719. std::error_code EC = makeAbsolute(Path);
  720. assert(!EC);
  721. (void)EC;
  722. if (useNormalizedPaths())
  723. llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
  724. if (Path.empty())
  725. return false;
  726. detail::InMemoryDirectory *Dir = Root.get();
  727. auto I = llvm::sys::path::begin(Path), E = sys::path::end(Path);
  728. const auto ResolvedUser = User.getValueOr(0);
  729. const auto ResolvedGroup = Group.getValueOr(0);
  730. const auto ResolvedType = Type.getValueOr(sys::fs::file_type::regular_file);
  731. const auto ResolvedPerms = Perms.getValueOr(sys::fs::all_all);
  732. // Any intermediate directories we create should be accessible by
  733. // the owner, even if Perms says otherwise for the final path.
  734. const auto NewDirectoryPerms = ResolvedPerms | sys::fs::owner_all;
  735. while (true) {
  736. StringRef Name = *I;
  737. detail::InMemoryNode *Node = Dir->getChild(Name);
  738. ++I;
  739. if (!Node) {
  740. if (I == E) {
  741. // End of the path.
  742. Dir->addChild(
  743. Name, MakeNode({Dir->getUniqueID(), Path, Name, ModificationTime,
  744. std::move(Buffer), ResolvedUser, ResolvedGroup,
  745. ResolvedType, ResolvedPerms}));
  746. return true;
  747. }
  748. // Create a new directory. Use the path up to here.
  749. Status Stat(
  750. StringRef(Path.str().begin(), Name.end() - Path.str().begin()),
  751. getDirectoryID(Dir->getUniqueID(), Name),
  752. llvm::sys::toTimePoint(ModificationTime), ResolvedUser, ResolvedGroup,
  753. 0, sys::fs::file_type::directory_file, NewDirectoryPerms);
  754. Dir = cast<detail::InMemoryDirectory>(Dir->addChild(
  755. Name, std::make_unique<detail::InMemoryDirectory>(std::move(Stat))));
  756. continue;
  757. }
  758. if (auto *NewDir = dyn_cast<detail::InMemoryDirectory>(Node)) {
  759. Dir = NewDir;
  760. } else {
  761. assert((isa<detail::InMemoryFile>(Node) ||
  762. isa<detail::InMemoryHardLink>(Node)) &&
  763. "Must be either file, hardlink or directory!");
  764. // Trying to insert a directory in place of a file.
  765. if (I != E)
  766. return false;
  767. // Return false only if the new file is different from the existing one.
  768. if (auto Link = dyn_cast<detail::InMemoryHardLink>(Node)) {
  769. return Link->getResolvedFile().getBuffer()->getBuffer() ==
  770. Buffer->getBuffer();
  771. }
  772. return cast<detail::InMemoryFile>(Node)->getBuffer()->getBuffer() ==
  773. Buffer->getBuffer();
  774. }
  775. }
  776. }
  777. bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime,
  778. std::unique_ptr<llvm::MemoryBuffer> Buffer,
  779. Optional<uint32_t> User,
  780. Optional<uint32_t> Group,
  781. Optional<llvm::sys::fs::file_type> Type,
  782. Optional<llvm::sys::fs::perms> Perms) {
  783. return addFile(P, ModificationTime, std::move(Buffer), User, Group, Type,
  784. Perms,
  785. [](detail::NewInMemoryNodeInfo NNI)
  786. -> std::unique_ptr<detail::InMemoryNode> {
  787. Status Stat = NNI.makeStatus();
  788. if (Stat.getType() == sys::fs::file_type::directory_file)
  789. return std::make_unique<detail::InMemoryDirectory>(Stat);
  790. return std::make_unique<detail::InMemoryFile>(
  791. Stat, std::move(NNI.Buffer));
  792. });
  793. }
  794. bool InMemoryFileSystem::addFileNoOwn(const Twine &P, time_t ModificationTime,
  795. const llvm::MemoryBufferRef &Buffer,
  796. Optional<uint32_t> User,
  797. Optional<uint32_t> Group,
  798. Optional<llvm::sys::fs::file_type> Type,
  799. Optional<llvm::sys::fs::perms> Perms) {
  800. return addFile(P, ModificationTime, llvm::MemoryBuffer::getMemBuffer(Buffer),
  801. std::move(User), std::move(Group), std::move(Type),
  802. std::move(Perms),
  803. [](detail::NewInMemoryNodeInfo NNI)
  804. -> std::unique_ptr<detail::InMemoryNode> {
  805. Status Stat = NNI.makeStatus();
  806. if (Stat.getType() == sys::fs::file_type::directory_file)
  807. return std::make_unique<detail::InMemoryDirectory>(Stat);
  808. return std::make_unique<detail::InMemoryFile>(
  809. Stat, std::move(NNI.Buffer));
  810. });
  811. }
  812. static ErrorOr<const detail::InMemoryNode *>
  813. lookupInMemoryNode(const InMemoryFileSystem &FS, detail::InMemoryDirectory *Dir,
  814. const Twine &P) {
  815. SmallString<128> Path;
  816. P.toVector(Path);
  817. // Fix up relative paths. This just prepends the current working directory.
  818. std::error_code EC = FS.makeAbsolute(Path);
  819. assert(!EC);
  820. (void)EC;
  821. if (FS.useNormalizedPaths())
  822. llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
  823. if (Path.empty())
  824. return Dir;
  825. auto I = llvm::sys::path::begin(Path), E = llvm::sys::path::end(Path);
  826. while (true) {
  827. detail::InMemoryNode *Node = Dir->getChild(*I);
  828. ++I;
  829. if (!Node)
  830. return errc::no_such_file_or_directory;
  831. // Return the file if it's at the end of the path.
  832. if (auto File = dyn_cast<detail::InMemoryFile>(Node)) {
  833. if (I == E)
  834. return File;
  835. return errc::no_such_file_or_directory;
  836. }
  837. // If Node is HardLink then return the resolved file.
  838. if (auto File = dyn_cast<detail::InMemoryHardLink>(Node)) {
  839. if (I == E)
  840. return &File->getResolvedFile();
  841. return errc::no_such_file_or_directory;
  842. }
  843. // Traverse directories.
  844. Dir = cast<detail::InMemoryDirectory>(Node);
  845. if (I == E)
  846. return Dir;
  847. }
  848. }
  849. bool InMemoryFileSystem::addHardLink(const Twine &FromPath,
  850. const Twine &ToPath) {
  851. auto FromNode = lookupInMemoryNode(*this, Root.get(), FromPath);
  852. auto ToNode = lookupInMemoryNode(*this, Root.get(), ToPath);
  853. // FromPath must not have been added before. ToPath must have been added
  854. // before. Resolved ToPath must be a File.
  855. if (!ToNode || FromNode || !isa<detail::InMemoryFile>(*ToNode))
  856. return false;
  857. return addFile(FromPath, 0, nullptr, None, None, None, None,
  858. [&](detail::NewInMemoryNodeInfo NNI) {
  859. return std::make_unique<detail::InMemoryHardLink>(
  860. NNI.Path.str(), *cast<detail::InMemoryFile>(*ToNode));
  861. });
  862. }
  863. llvm::ErrorOr<Status> InMemoryFileSystem::status(const Twine &Path) {
  864. auto Node = lookupInMemoryNode(*this, Root.get(), Path);
  865. if (Node)
  866. return (*Node)->getStatus(Path);
  867. return Node.getError();
  868. }
  869. llvm::ErrorOr<std::unique_ptr<File>>
  870. InMemoryFileSystem::openFileForRead(const Twine &Path) {
  871. auto Node = lookupInMemoryNode(*this, Root.get(), Path);
  872. if (!Node)
  873. return Node.getError();
  874. // When we have a file provide a heap-allocated wrapper for the memory buffer
  875. // to match the ownership semantics for File.
  876. if (auto *F = dyn_cast<detail::InMemoryFile>(*Node))
  877. return std::unique_ptr<File>(
  878. new detail::InMemoryFileAdaptor(*F, Path.str()));
  879. // FIXME: errc::not_a_file?
  880. return make_error_code(llvm::errc::invalid_argument);
  881. }
  882. namespace {
  883. /// Adaptor from InMemoryDir::iterator to directory_iterator.
  884. class InMemoryDirIterator : public llvm::vfs::detail::DirIterImpl {
  885. detail::InMemoryDirectory::const_iterator I;
  886. detail::InMemoryDirectory::const_iterator E;
  887. std::string RequestedDirName;
  888. void setCurrentEntry() {
  889. if (I != E) {
  890. SmallString<256> Path(RequestedDirName);
  891. llvm::sys::path::append(Path, I->second->getFileName());
  892. sys::fs::file_type Type = sys::fs::file_type::type_unknown;
  893. switch (I->second->getKind()) {
  894. case detail::IME_File:
  895. case detail::IME_HardLink:
  896. Type = sys::fs::file_type::regular_file;
  897. break;
  898. case detail::IME_Directory:
  899. Type = sys::fs::file_type::directory_file;
  900. break;
  901. }
  902. CurrentEntry = directory_entry(std::string(Path.str()), Type);
  903. } else {
  904. // When we're at the end, make CurrentEntry invalid and DirIterImpl will
  905. // do the rest.
  906. CurrentEntry = directory_entry();
  907. }
  908. }
  909. public:
  910. InMemoryDirIterator() = default;
  911. explicit InMemoryDirIterator(const detail::InMemoryDirectory &Dir,
  912. std::string RequestedDirName)
  913. : I(Dir.begin()), E(Dir.end()),
  914. RequestedDirName(std::move(RequestedDirName)) {
  915. setCurrentEntry();
  916. }
  917. std::error_code increment() override {
  918. ++I;
  919. setCurrentEntry();
  920. return {};
  921. }
  922. };
  923. } // namespace
  924. directory_iterator InMemoryFileSystem::dir_begin(const Twine &Dir,
  925. std::error_code &EC) {
  926. auto Node = lookupInMemoryNode(*this, Root.get(), Dir);
  927. if (!Node) {
  928. EC = Node.getError();
  929. return directory_iterator(std::make_shared<InMemoryDirIterator>());
  930. }
  931. if (auto *DirNode = dyn_cast<detail::InMemoryDirectory>(*Node))
  932. return directory_iterator(
  933. std::make_shared<InMemoryDirIterator>(*DirNode, Dir.str()));
  934. EC = make_error_code(llvm::errc::not_a_directory);
  935. return directory_iterator(std::make_shared<InMemoryDirIterator>());
  936. }
  937. std::error_code InMemoryFileSystem::setCurrentWorkingDirectory(const Twine &P) {
  938. SmallString<128> Path;
  939. P.toVector(Path);
  940. // Fix up relative paths. This just prepends the current working directory.
  941. std::error_code EC = makeAbsolute(Path);
  942. assert(!EC);
  943. (void)EC;
  944. if (useNormalizedPaths())
  945. llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
  946. if (!Path.empty())
  947. WorkingDirectory = std::string(Path.str());
  948. return {};
  949. }
  950. std::error_code
  951. InMemoryFileSystem::getRealPath(const Twine &Path,
  952. SmallVectorImpl<char> &Output) const {
  953. auto CWD = getCurrentWorkingDirectory();
  954. if (!CWD || CWD->empty())
  955. return errc::operation_not_permitted;
  956. Path.toVector(Output);
  957. if (auto EC = makeAbsolute(Output))
  958. return EC;
  959. llvm::sys::path::remove_dots(Output, /*remove_dot_dot=*/true);
  960. return {};
  961. }
  962. std::error_code InMemoryFileSystem::isLocal(const Twine &Path, bool &Result) {
  963. Result = false;
  964. return {};
  965. }
  966. } // namespace vfs
  967. } // namespace llvm
  968. //===-----------------------------------------------------------------------===/
  969. // RedirectingFileSystem implementation
  970. //===-----------------------------------------------------------------------===/
  971. namespace {
  972. static llvm::sys::path::Style getExistingStyle(llvm::StringRef Path) {
  973. // Detect the path style in use by checking the first separator.
  974. llvm::sys::path::Style style = llvm::sys::path::Style::native;
  975. const size_t n = Path.find_first_of("/\\");
  976. // Can't distinguish between posix and windows_slash here.
  977. if (n != static_cast<size_t>(-1))
  978. style = (Path[n] == '/') ? llvm::sys::path::Style::posix
  979. : llvm::sys::path::Style::windows_backslash;
  980. return style;
  981. }
  982. /// Removes leading "./" as well as path components like ".." and ".".
  983. static llvm::SmallString<256> canonicalize(llvm::StringRef Path) {
  984. // First detect the path style in use by checking the first separator.
  985. llvm::sys::path::Style style = getExistingStyle(Path);
  986. // Now remove the dots. Explicitly specifying the path style prevents the
  987. // direction of the slashes from changing.
  988. llvm::SmallString<256> result =
  989. llvm::sys::path::remove_leading_dotslash(Path, style);
  990. llvm::sys::path::remove_dots(result, /*remove_dot_dot=*/true, style);
  991. return result;
  992. }
  993. } // anonymous namespace
  994. RedirectingFileSystem::RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> FS)
  995. : ExternalFS(std::move(FS)) {
  996. if (ExternalFS)
  997. if (auto ExternalWorkingDirectory =
  998. ExternalFS->getCurrentWorkingDirectory()) {
  999. WorkingDirectory = *ExternalWorkingDirectory;
  1000. }
  1001. }
  1002. /// Directory iterator implementation for \c RedirectingFileSystem's
  1003. /// directory entries.
  1004. class llvm::vfs::RedirectingFSDirIterImpl
  1005. : public llvm::vfs::detail::DirIterImpl {
  1006. std::string Dir;
  1007. RedirectingFileSystem::DirectoryEntry::iterator Current, End;
  1008. std::error_code incrementImpl(bool IsFirstTime) {
  1009. assert((IsFirstTime || Current != End) && "cannot iterate past end");
  1010. if (!IsFirstTime)
  1011. ++Current;
  1012. if (Current != End) {
  1013. SmallString<128> PathStr(Dir);
  1014. llvm::sys::path::append(PathStr, (*Current)->getName());
  1015. sys::fs::file_type Type = sys::fs::file_type::type_unknown;
  1016. switch ((*Current)->getKind()) {
  1017. case RedirectingFileSystem::EK_Directory:
  1018. LLVM_FALLTHROUGH;
  1019. case RedirectingFileSystem::EK_DirectoryRemap:
  1020. Type = sys::fs::file_type::directory_file;
  1021. break;
  1022. case RedirectingFileSystem::EK_File:
  1023. Type = sys::fs::file_type::regular_file;
  1024. break;
  1025. }
  1026. CurrentEntry = directory_entry(std::string(PathStr.str()), Type);
  1027. } else {
  1028. CurrentEntry = directory_entry();
  1029. }
  1030. return {};
  1031. };
  1032. public:
  1033. RedirectingFSDirIterImpl(
  1034. const Twine &Path, RedirectingFileSystem::DirectoryEntry::iterator Begin,
  1035. RedirectingFileSystem::DirectoryEntry::iterator End, std::error_code &EC)
  1036. : Dir(Path.str()), Current(Begin), End(End) {
  1037. EC = incrementImpl(/*IsFirstTime=*/true);
  1038. }
  1039. std::error_code increment() override {
  1040. return incrementImpl(/*IsFirstTime=*/false);
  1041. }
  1042. };
  1043. namespace {
  1044. /// Directory iterator implementation for \c RedirectingFileSystem's
  1045. /// directory remap entries that maps the paths reported by the external
  1046. /// file system's directory iterator back to the virtual directory's path.
  1047. class RedirectingFSDirRemapIterImpl : public llvm::vfs::detail::DirIterImpl {
  1048. std::string Dir;
  1049. llvm::sys::path::Style DirStyle;
  1050. llvm::vfs::directory_iterator ExternalIter;
  1051. public:
  1052. RedirectingFSDirRemapIterImpl(std::string DirPath,
  1053. llvm::vfs::directory_iterator ExtIter)
  1054. : Dir(std::move(DirPath)), DirStyle(getExistingStyle(Dir)),
  1055. ExternalIter(ExtIter) {
  1056. if (ExternalIter != llvm::vfs::directory_iterator())
  1057. setCurrentEntry();
  1058. }
  1059. void setCurrentEntry() {
  1060. StringRef ExternalPath = ExternalIter->path();
  1061. llvm::sys::path::Style ExternalStyle = getExistingStyle(ExternalPath);
  1062. StringRef File = llvm::sys::path::filename(ExternalPath, ExternalStyle);
  1063. SmallString<128> NewPath(Dir);
  1064. llvm::sys::path::append(NewPath, DirStyle, File);
  1065. CurrentEntry = directory_entry(std::string(NewPath), ExternalIter->type());
  1066. }
  1067. std::error_code increment() override {
  1068. std::error_code EC;
  1069. ExternalIter.increment(EC);
  1070. if (!EC && ExternalIter != llvm::vfs::directory_iterator())
  1071. setCurrentEntry();
  1072. else
  1073. CurrentEntry = directory_entry();
  1074. return EC;
  1075. }
  1076. };
  1077. } // namespace
  1078. llvm::ErrorOr<std::string>
  1079. RedirectingFileSystem::getCurrentWorkingDirectory() const {
  1080. return WorkingDirectory;
  1081. }
  1082. std::error_code
  1083. RedirectingFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
  1084. // Don't change the working directory if the path doesn't exist.
  1085. if (!exists(Path))
  1086. return errc::no_such_file_or_directory;
  1087. SmallString<128> AbsolutePath;
  1088. Path.toVector(AbsolutePath);
  1089. if (std::error_code EC = makeAbsolute(AbsolutePath))
  1090. return EC;
  1091. WorkingDirectory = std::string(AbsolutePath.str());
  1092. return {};
  1093. }
  1094. std::error_code RedirectingFileSystem::isLocal(const Twine &Path_,
  1095. bool &Result) {
  1096. SmallString<256> Path;
  1097. Path_.toVector(Path);
  1098. if (std::error_code EC = makeCanonical(Path))
  1099. return {};
  1100. return ExternalFS->isLocal(Path, Result);
  1101. }
  1102. std::error_code RedirectingFileSystem::makeAbsolute(SmallVectorImpl<char> &Path) const {
  1103. // is_absolute(..., Style::windows_*) accepts paths with both slash types.
  1104. if (llvm::sys::path::is_absolute(Path, llvm::sys::path::Style::posix) ||
  1105. llvm::sys::path::is_absolute(Path,
  1106. llvm::sys::path::Style::windows_backslash))
  1107. return {};
  1108. auto WorkingDir = getCurrentWorkingDirectory();
  1109. if (!WorkingDir)
  1110. return WorkingDir.getError();
  1111. // We can't use sys::fs::make_absolute because that assumes the path style
  1112. // is native and there is no way to override that. Since we know WorkingDir
  1113. // is absolute, we can use it to determine which style we actually have and
  1114. // append Path ourselves.
  1115. sys::path::Style style = sys::path::Style::windows_backslash;
  1116. if (sys::path::is_absolute(WorkingDir.get(), sys::path::Style::posix)) {
  1117. style = sys::path::Style::posix;
  1118. } else {
  1119. // Distinguish between windows_backslash and windows_slash; getExistingStyle
  1120. // returns posix for a path with windows_slash.
  1121. if (getExistingStyle(WorkingDir.get()) !=
  1122. sys::path::Style::windows_backslash)
  1123. style = sys::path::Style::windows_slash;
  1124. }
  1125. std::string Result = WorkingDir.get();
  1126. StringRef Dir(Result);
  1127. if (!Dir.endswith(sys::path::get_separator(style))) {
  1128. Result += sys::path::get_separator(style);
  1129. }
  1130. Result.append(Path.data(), Path.size());
  1131. Path.assign(Result.begin(), Result.end());
  1132. return {};
  1133. }
  1134. directory_iterator RedirectingFileSystem::dir_begin(const Twine &Dir,
  1135. std::error_code &EC) {
  1136. SmallString<256> Path;
  1137. Dir.toVector(Path);
  1138. EC = makeCanonical(Path);
  1139. if (EC)
  1140. return {};
  1141. ErrorOr<RedirectingFileSystem::LookupResult> Result = lookupPath(Path);
  1142. if (!Result) {
  1143. EC = Result.getError();
  1144. if (shouldFallBackToExternalFS(EC))
  1145. return ExternalFS->dir_begin(Path, EC);
  1146. return {};
  1147. }
  1148. // Use status to make sure the path exists and refers to a directory.
  1149. ErrorOr<Status> S = status(Path, Dir, *Result);
  1150. if (!S) {
  1151. if (shouldFallBackToExternalFS(S.getError(), Result->E))
  1152. return ExternalFS->dir_begin(Dir, EC);
  1153. EC = S.getError();
  1154. return {};
  1155. }
  1156. if (!S->isDirectory()) {
  1157. EC = std::error_code(static_cast<int>(errc::not_a_directory),
  1158. std::system_category());
  1159. return {};
  1160. }
  1161. // Create the appropriate directory iterator based on whether we found a
  1162. // DirectoryRemapEntry or DirectoryEntry.
  1163. directory_iterator DirIter;
  1164. if (auto ExtRedirect = Result->getExternalRedirect()) {
  1165. auto RE = cast<RedirectingFileSystem::RemapEntry>(Result->E);
  1166. DirIter = ExternalFS->dir_begin(*ExtRedirect, EC);
  1167. if (!RE->useExternalName(UseExternalNames)) {
  1168. // Update the paths in the results to use the virtual directory's path.
  1169. DirIter =
  1170. directory_iterator(std::make_shared<RedirectingFSDirRemapIterImpl>(
  1171. std::string(Path), DirIter));
  1172. }
  1173. } else {
  1174. auto DE = cast<DirectoryEntry>(Result->E);
  1175. DirIter = directory_iterator(std::make_shared<RedirectingFSDirIterImpl>(
  1176. Path, DE->contents_begin(), DE->contents_end(), EC));
  1177. }
  1178. if (!shouldUseExternalFS())
  1179. return DirIter;
  1180. return directory_iterator(std::make_shared<CombiningDirIterImpl>(
  1181. DirIter, ExternalFS, std::string(Path), EC));
  1182. }
  1183. void RedirectingFileSystem::setExternalContentsPrefixDir(StringRef PrefixDir) {
  1184. ExternalContentsPrefixDir = PrefixDir.str();
  1185. }
  1186. StringRef RedirectingFileSystem::getExternalContentsPrefixDir() const {
  1187. return ExternalContentsPrefixDir;
  1188. }
  1189. void RedirectingFileSystem::setFallthrough(bool Fallthrough) {
  1190. IsFallthrough = Fallthrough;
  1191. }
  1192. std::vector<StringRef> RedirectingFileSystem::getRoots() const {
  1193. std::vector<StringRef> R;
  1194. for (const auto &Root : Roots)
  1195. R.push_back(Root->getName());
  1196. return R;
  1197. }
  1198. void RedirectingFileSystem::dump(raw_ostream &OS) const {
  1199. for (const auto &Root : Roots)
  1200. dumpEntry(OS, Root.get());
  1201. }
  1202. void RedirectingFileSystem::dumpEntry(raw_ostream &OS,
  1203. RedirectingFileSystem::Entry *E,
  1204. int NumSpaces) const {
  1205. StringRef Name = E->getName();
  1206. for (int i = 0, e = NumSpaces; i < e; ++i)
  1207. OS << " ";
  1208. OS << "'" << Name.str().c_str() << "'"
  1209. << "\n";
  1210. if (E->getKind() == RedirectingFileSystem::EK_Directory) {
  1211. auto *DE = dyn_cast<RedirectingFileSystem::DirectoryEntry>(E);
  1212. assert(DE && "Should be a directory");
  1213. for (std::unique_ptr<Entry> &SubEntry :
  1214. llvm::make_range(DE->contents_begin(), DE->contents_end()))
  1215. dumpEntry(OS, SubEntry.get(), NumSpaces + 2);
  1216. }
  1217. }
  1218. #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
  1219. LLVM_DUMP_METHOD void RedirectingFileSystem::dump() const { dump(dbgs()); }
  1220. #endif
  1221. /// A helper class to hold the common YAML parsing state.
  1222. class llvm::vfs::RedirectingFileSystemParser {
  1223. yaml::Stream &Stream;
  1224. void error(yaml::Node *N, const Twine &Msg) { Stream.printError(N, Msg); }
  1225. // false on error
  1226. bool parseScalarString(yaml::Node *N, StringRef &Result,
  1227. SmallVectorImpl<char> &Storage) {
  1228. const auto *S = dyn_cast<yaml::ScalarNode>(N);
  1229. if (!S) {
  1230. error(N, "expected string");
  1231. return false;
  1232. }
  1233. Result = S->getValue(Storage);
  1234. return true;
  1235. }
  1236. // false on error
  1237. bool parseScalarBool(yaml::Node *N, bool &Result) {
  1238. SmallString<5> Storage;
  1239. StringRef Value;
  1240. if (!parseScalarString(N, Value, Storage))
  1241. return false;
  1242. if (Value.equals_insensitive("true") || Value.equals_insensitive("on") ||
  1243. Value.equals_insensitive("yes") || Value == "1") {
  1244. Result = true;
  1245. return true;
  1246. } else if (Value.equals_insensitive("false") ||
  1247. Value.equals_insensitive("off") ||
  1248. Value.equals_insensitive("no") || Value == "0") {
  1249. Result = false;
  1250. return true;
  1251. }
  1252. error(N, "expected boolean value");
  1253. return false;
  1254. }
  1255. struct KeyStatus {
  1256. bool Required;
  1257. bool Seen = false;
  1258. KeyStatus(bool Required = false) : Required(Required) {}
  1259. };
  1260. using KeyStatusPair = std::pair<StringRef, KeyStatus>;
  1261. // false on error
  1262. bool checkDuplicateOrUnknownKey(yaml::Node *KeyNode, StringRef Key,
  1263. DenseMap<StringRef, KeyStatus> &Keys) {
  1264. if (!Keys.count(Key)) {
  1265. error(KeyNode, "unknown key");
  1266. return false;
  1267. }
  1268. KeyStatus &S = Keys[Key];
  1269. if (S.Seen) {
  1270. error(KeyNode, Twine("duplicate key '") + Key + "'");
  1271. return false;
  1272. }
  1273. S.Seen = true;
  1274. return true;
  1275. }
  1276. // false on error
  1277. bool checkMissingKeys(yaml::Node *Obj, DenseMap<StringRef, KeyStatus> &Keys) {
  1278. for (const auto &I : Keys) {
  1279. if (I.second.Required && !I.second.Seen) {
  1280. error(Obj, Twine("missing key '") + I.first + "'");
  1281. return false;
  1282. }
  1283. }
  1284. return true;
  1285. }
  1286. public:
  1287. static RedirectingFileSystem::Entry *
  1288. lookupOrCreateEntry(RedirectingFileSystem *FS, StringRef Name,
  1289. RedirectingFileSystem::Entry *ParentEntry = nullptr) {
  1290. if (!ParentEntry) { // Look for a existent root
  1291. for (const auto &Root : FS->Roots) {
  1292. if (Name.equals(Root->getName())) {
  1293. ParentEntry = Root.get();
  1294. return ParentEntry;
  1295. }
  1296. }
  1297. } else { // Advance to the next component
  1298. auto *DE = dyn_cast<RedirectingFileSystem::DirectoryEntry>(ParentEntry);
  1299. for (std::unique_ptr<RedirectingFileSystem::Entry> &Content :
  1300. llvm::make_range(DE->contents_begin(), DE->contents_end())) {
  1301. auto *DirContent =
  1302. dyn_cast<RedirectingFileSystem::DirectoryEntry>(Content.get());
  1303. if (DirContent && Name.equals(Content->getName()))
  1304. return DirContent;
  1305. }
  1306. }
  1307. // ... or create a new one
  1308. std::unique_ptr<RedirectingFileSystem::Entry> E =
  1309. std::make_unique<RedirectingFileSystem::DirectoryEntry>(
  1310. Name, Status("", getNextVirtualUniqueID(),
  1311. std::chrono::system_clock::now(), 0, 0, 0,
  1312. file_type::directory_file, sys::fs::all_all));
  1313. if (!ParentEntry) { // Add a new root to the overlay
  1314. FS->Roots.push_back(std::move(E));
  1315. ParentEntry = FS->Roots.back().get();
  1316. return ParentEntry;
  1317. }
  1318. auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(ParentEntry);
  1319. DE->addContent(std::move(E));
  1320. return DE->getLastContent();
  1321. }
  1322. private:
  1323. void uniqueOverlayTree(RedirectingFileSystem *FS,
  1324. RedirectingFileSystem::Entry *SrcE,
  1325. RedirectingFileSystem::Entry *NewParentE = nullptr) {
  1326. StringRef Name = SrcE->getName();
  1327. switch (SrcE->getKind()) {
  1328. case RedirectingFileSystem::EK_Directory: {
  1329. auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(SrcE);
  1330. // Empty directories could be present in the YAML as a way to
  1331. // describe a file for a current directory after some of its subdir
  1332. // is parsed. This only leads to redundant walks, ignore it.
  1333. if (!Name.empty())
  1334. NewParentE = lookupOrCreateEntry(FS, Name, NewParentE);
  1335. for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
  1336. llvm::make_range(DE->contents_begin(), DE->contents_end()))
  1337. uniqueOverlayTree(FS, SubEntry.get(), NewParentE);
  1338. break;
  1339. }
  1340. case RedirectingFileSystem::EK_DirectoryRemap: {
  1341. assert(NewParentE && "Parent entry must exist");
  1342. auto *DR = cast<RedirectingFileSystem::DirectoryRemapEntry>(SrcE);
  1343. auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(NewParentE);
  1344. DE->addContent(
  1345. std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
  1346. Name, DR->getExternalContentsPath(), DR->getUseName()));
  1347. break;
  1348. }
  1349. case RedirectingFileSystem::EK_File: {
  1350. assert(NewParentE && "Parent entry must exist");
  1351. auto *FE = cast<RedirectingFileSystem::FileEntry>(SrcE);
  1352. auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(NewParentE);
  1353. DE->addContent(std::make_unique<RedirectingFileSystem::FileEntry>(
  1354. Name, FE->getExternalContentsPath(), FE->getUseName()));
  1355. break;
  1356. }
  1357. }
  1358. }
  1359. std::unique_ptr<RedirectingFileSystem::Entry>
  1360. parseEntry(yaml::Node *N, RedirectingFileSystem *FS, bool IsRootEntry) {
  1361. auto *M = dyn_cast<yaml::MappingNode>(N);
  1362. if (!M) {
  1363. error(N, "expected mapping node for file or directory entry");
  1364. return nullptr;
  1365. }
  1366. KeyStatusPair Fields[] = {
  1367. KeyStatusPair("name", true),
  1368. KeyStatusPair("type", true),
  1369. KeyStatusPair("contents", false),
  1370. KeyStatusPair("external-contents", false),
  1371. KeyStatusPair("use-external-name", false),
  1372. };
  1373. DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields));
  1374. enum { CF_NotSet, CF_List, CF_External } ContentsField = CF_NotSet;
  1375. std::vector<std::unique_ptr<RedirectingFileSystem::Entry>>
  1376. EntryArrayContents;
  1377. SmallString<256> ExternalContentsPath;
  1378. SmallString<256> Name;
  1379. yaml::Node *NameValueNode = nullptr;
  1380. auto UseExternalName = RedirectingFileSystem::NK_NotSet;
  1381. RedirectingFileSystem::EntryKind Kind;
  1382. for (auto &I : *M) {
  1383. StringRef Key;
  1384. // Reuse the buffer for key and value, since we don't look at key after
  1385. // parsing value.
  1386. SmallString<256> Buffer;
  1387. if (!parseScalarString(I.getKey(), Key, Buffer))
  1388. return nullptr;
  1389. if (!checkDuplicateOrUnknownKey(I.getKey(), Key, Keys))
  1390. return nullptr;
  1391. StringRef Value;
  1392. if (Key == "name") {
  1393. if (!parseScalarString(I.getValue(), Value, Buffer))
  1394. return nullptr;
  1395. NameValueNode = I.getValue();
  1396. // Guarantee that old YAML files containing paths with ".." and "."
  1397. // are properly canonicalized before read into the VFS.
  1398. Name = canonicalize(Value).str();
  1399. } else if (Key == "type") {
  1400. if (!parseScalarString(I.getValue(), Value, Buffer))
  1401. return nullptr;
  1402. if (Value == "file")
  1403. Kind = RedirectingFileSystem::EK_File;
  1404. else if (Value == "directory")
  1405. Kind = RedirectingFileSystem::EK_Directory;
  1406. else if (Value == "directory-remap")
  1407. Kind = RedirectingFileSystem::EK_DirectoryRemap;
  1408. else {
  1409. error(I.getValue(), "unknown value for 'type'");
  1410. return nullptr;
  1411. }
  1412. } else if (Key == "contents") {
  1413. if (ContentsField != CF_NotSet) {
  1414. error(I.getKey(),
  1415. "entry already has 'contents' or 'external-contents'");
  1416. return nullptr;
  1417. }
  1418. ContentsField = CF_List;
  1419. auto *Contents = dyn_cast<yaml::SequenceNode>(I.getValue());
  1420. if (!Contents) {
  1421. // FIXME: this is only for directories, what about files?
  1422. error(I.getValue(), "expected array");
  1423. return nullptr;
  1424. }
  1425. for (auto &I : *Contents) {
  1426. if (std::unique_ptr<RedirectingFileSystem::Entry> E =
  1427. parseEntry(&I, FS, /*IsRootEntry*/ false))
  1428. EntryArrayContents.push_back(std::move(E));
  1429. else
  1430. return nullptr;
  1431. }
  1432. } else if (Key == "external-contents") {
  1433. if (ContentsField != CF_NotSet) {
  1434. error(I.getKey(),
  1435. "entry already has 'contents' or 'external-contents'");
  1436. return nullptr;
  1437. }
  1438. ContentsField = CF_External;
  1439. if (!parseScalarString(I.getValue(), Value, Buffer))
  1440. return nullptr;
  1441. SmallString<256> FullPath;
  1442. if (FS->IsRelativeOverlay) {
  1443. FullPath = FS->getExternalContentsPrefixDir();
  1444. assert(!FullPath.empty() &&
  1445. "External contents prefix directory must exist");
  1446. llvm::sys::path::append(FullPath, Value);
  1447. } else {
  1448. FullPath = Value;
  1449. }
  1450. // Guarantee that old YAML files containing paths with ".." and "."
  1451. // are properly canonicalized before read into the VFS.
  1452. FullPath = canonicalize(FullPath);
  1453. ExternalContentsPath = FullPath.str();
  1454. } else if (Key == "use-external-name") {
  1455. bool Val;
  1456. if (!parseScalarBool(I.getValue(), Val))
  1457. return nullptr;
  1458. UseExternalName = Val ? RedirectingFileSystem::NK_External
  1459. : RedirectingFileSystem::NK_Virtual;
  1460. } else {
  1461. llvm_unreachable("key missing from Keys");
  1462. }
  1463. }
  1464. if (Stream.failed())
  1465. return nullptr;
  1466. // check for missing keys
  1467. if (ContentsField == CF_NotSet) {
  1468. error(N, "missing key 'contents' or 'external-contents'");
  1469. return nullptr;
  1470. }
  1471. if (!checkMissingKeys(N, Keys))
  1472. return nullptr;
  1473. // check invalid configuration
  1474. if (Kind == RedirectingFileSystem::EK_Directory &&
  1475. UseExternalName != RedirectingFileSystem::NK_NotSet) {
  1476. error(N, "'use-external-name' is not supported for 'directory' entries");
  1477. return nullptr;
  1478. }
  1479. if (Kind == RedirectingFileSystem::EK_DirectoryRemap &&
  1480. ContentsField == CF_List) {
  1481. error(N, "'contents' is not supported for 'directory-remap' entries");
  1482. return nullptr;
  1483. }
  1484. sys::path::Style path_style = sys::path::Style::native;
  1485. if (IsRootEntry) {
  1486. // VFS root entries may be in either Posix or Windows style. Figure out
  1487. // which style we have, and use it consistently.
  1488. if (sys::path::is_absolute(Name, sys::path::Style::posix)) {
  1489. path_style = sys::path::Style::posix;
  1490. } else if (sys::path::is_absolute(Name,
  1491. sys::path::Style::windows_backslash)) {
  1492. path_style = sys::path::Style::windows_backslash;
  1493. } else {
  1494. // Relative VFS root entries are made absolute to the current working
  1495. // directory, then we can determine the path style from that.
  1496. auto EC = sys::fs::make_absolute(Name);
  1497. if (EC) {
  1498. assert(NameValueNode && "Name presence should be checked earlier");
  1499. error(
  1500. NameValueNode,
  1501. "entry with relative path at the root level is not discoverable");
  1502. return nullptr;
  1503. }
  1504. path_style = sys::path::is_absolute(Name, sys::path::Style::posix)
  1505. ? sys::path::Style::posix
  1506. : sys::path::Style::windows_backslash;
  1507. }
  1508. }
  1509. // Remove trailing slash(es), being careful not to remove the root path
  1510. StringRef Trimmed = Name;
  1511. size_t RootPathLen = sys::path::root_path(Trimmed, path_style).size();
  1512. while (Trimmed.size() > RootPathLen &&
  1513. sys::path::is_separator(Trimmed.back(), path_style))
  1514. Trimmed = Trimmed.slice(0, Trimmed.size() - 1);
  1515. // Get the last component
  1516. StringRef LastComponent = sys::path::filename(Trimmed, path_style);
  1517. std::unique_ptr<RedirectingFileSystem::Entry> Result;
  1518. switch (Kind) {
  1519. case RedirectingFileSystem::EK_File:
  1520. Result = std::make_unique<RedirectingFileSystem::FileEntry>(
  1521. LastComponent, std::move(ExternalContentsPath), UseExternalName);
  1522. break;
  1523. case RedirectingFileSystem::EK_DirectoryRemap:
  1524. Result = std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
  1525. LastComponent, std::move(ExternalContentsPath), UseExternalName);
  1526. break;
  1527. case RedirectingFileSystem::EK_Directory:
  1528. Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
  1529. LastComponent, std::move(EntryArrayContents),
  1530. Status("", getNextVirtualUniqueID(), std::chrono::system_clock::now(),
  1531. 0, 0, 0, file_type::directory_file, sys::fs::all_all));
  1532. break;
  1533. }
  1534. StringRef Parent = sys::path::parent_path(Trimmed, path_style);
  1535. if (Parent.empty())
  1536. return Result;
  1537. // if 'name' contains multiple components, create implicit directory entries
  1538. for (sys::path::reverse_iterator I = sys::path::rbegin(Parent, path_style),
  1539. E = sys::path::rend(Parent);
  1540. I != E; ++I) {
  1541. std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> Entries;
  1542. Entries.push_back(std::move(Result));
  1543. Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
  1544. *I, std::move(Entries),
  1545. Status("", getNextVirtualUniqueID(), std::chrono::system_clock::now(),
  1546. 0, 0, 0, file_type::directory_file, sys::fs::all_all));
  1547. }
  1548. return Result;
  1549. }
  1550. public:
  1551. RedirectingFileSystemParser(yaml::Stream &S) : Stream(S) {}
  1552. // false on error
  1553. bool parse(yaml::Node *Root, RedirectingFileSystem *FS) {
  1554. auto *Top = dyn_cast<yaml::MappingNode>(Root);
  1555. if (!Top) {
  1556. error(Root, "expected mapping node");
  1557. return false;
  1558. }
  1559. KeyStatusPair Fields[] = {
  1560. KeyStatusPair("version", true),
  1561. KeyStatusPair("case-sensitive", false),
  1562. KeyStatusPair("use-external-names", false),
  1563. KeyStatusPair("overlay-relative", false),
  1564. KeyStatusPair("fallthrough", false),
  1565. KeyStatusPair("roots", true),
  1566. };
  1567. DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields));
  1568. std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> RootEntries;
  1569. // Parse configuration and 'roots'
  1570. for (auto &I : *Top) {
  1571. SmallString<10> KeyBuffer;
  1572. StringRef Key;
  1573. if (!parseScalarString(I.getKey(), Key, KeyBuffer))
  1574. return false;
  1575. if (!checkDuplicateOrUnknownKey(I.getKey(), Key, Keys))
  1576. return false;
  1577. if (Key == "roots") {
  1578. auto *Roots = dyn_cast<yaml::SequenceNode>(I.getValue());
  1579. if (!Roots) {
  1580. error(I.getValue(), "expected array");
  1581. return false;
  1582. }
  1583. for (auto &I : *Roots) {
  1584. if (std::unique_ptr<RedirectingFileSystem::Entry> E =
  1585. parseEntry(&I, FS, /*IsRootEntry*/ true))
  1586. RootEntries.push_back(std::move(E));
  1587. else
  1588. return false;
  1589. }
  1590. } else if (Key == "version") {
  1591. StringRef VersionString;
  1592. SmallString<4> Storage;
  1593. if (!parseScalarString(I.getValue(), VersionString, Storage))
  1594. return false;
  1595. int Version;
  1596. if (VersionString.getAsInteger<int>(10, Version)) {
  1597. error(I.getValue(), "expected integer");
  1598. return false;
  1599. }
  1600. if (Version < 0) {
  1601. error(I.getValue(), "invalid version number");
  1602. return false;
  1603. }
  1604. if (Version != 0) {
  1605. error(I.getValue(), "version mismatch, expected 0");
  1606. return false;
  1607. }
  1608. } else if (Key == "case-sensitive") {
  1609. if (!parseScalarBool(I.getValue(), FS->CaseSensitive))
  1610. return false;
  1611. } else if (Key == "overlay-relative") {
  1612. if (!parseScalarBool(I.getValue(), FS->IsRelativeOverlay))
  1613. return false;
  1614. } else if (Key == "use-external-names") {
  1615. if (!parseScalarBool(I.getValue(), FS->UseExternalNames))
  1616. return false;
  1617. } else if (Key == "fallthrough") {
  1618. if (!parseScalarBool(I.getValue(), FS->IsFallthrough))
  1619. return false;
  1620. } else {
  1621. llvm_unreachable("key missing from Keys");
  1622. }
  1623. }
  1624. if (Stream.failed())
  1625. return false;
  1626. if (!checkMissingKeys(Top, Keys))
  1627. return false;
  1628. // Now that we sucessefully parsed the YAML file, canonicalize the internal
  1629. // representation to a proper directory tree so that we can search faster
  1630. // inside the VFS.
  1631. for (auto &E : RootEntries)
  1632. uniqueOverlayTree(FS, E.get());
  1633. return true;
  1634. }
  1635. };
  1636. std::unique_ptr<RedirectingFileSystem>
  1637. RedirectingFileSystem::create(std::unique_ptr<MemoryBuffer> Buffer,
  1638. SourceMgr::DiagHandlerTy DiagHandler,
  1639. StringRef YAMLFilePath, void *DiagContext,
  1640. IntrusiveRefCntPtr<FileSystem> ExternalFS) {
  1641. SourceMgr SM;
  1642. yaml::Stream Stream(Buffer->getMemBufferRef(), SM);
  1643. SM.setDiagHandler(DiagHandler, DiagContext);
  1644. yaml::document_iterator DI = Stream.begin();
  1645. yaml::Node *Root = DI->getRoot();
  1646. if (DI == Stream.end() || !Root) {
  1647. SM.PrintMessage(SMLoc(), SourceMgr::DK_Error, "expected root node");
  1648. return nullptr;
  1649. }
  1650. RedirectingFileSystemParser P(Stream);
  1651. std::unique_ptr<RedirectingFileSystem> FS(
  1652. new RedirectingFileSystem(ExternalFS));
  1653. if (!YAMLFilePath.empty()) {
  1654. // Use the YAML path from -ivfsoverlay to compute the dir to be prefixed
  1655. // to each 'external-contents' path.
  1656. //
  1657. // Example:
  1658. // -ivfsoverlay dummy.cache/vfs/vfs.yaml
  1659. // yields:
  1660. // FS->ExternalContentsPrefixDir => /<absolute_path_to>/dummy.cache/vfs
  1661. //
  1662. SmallString<256> OverlayAbsDir = sys::path::parent_path(YAMLFilePath);
  1663. std::error_code EC = llvm::sys::fs::make_absolute(OverlayAbsDir);
  1664. assert(!EC && "Overlay dir final path must be absolute");
  1665. (void)EC;
  1666. FS->setExternalContentsPrefixDir(OverlayAbsDir);
  1667. }
  1668. if (!P.parse(Root, FS.get()))
  1669. return nullptr;
  1670. return FS;
  1671. }
  1672. std::unique_ptr<RedirectingFileSystem> RedirectingFileSystem::create(
  1673. ArrayRef<std::pair<std::string, std::string>> RemappedFiles,
  1674. bool UseExternalNames, FileSystem &ExternalFS) {
  1675. std::unique_ptr<RedirectingFileSystem> FS(
  1676. new RedirectingFileSystem(&ExternalFS));
  1677. FS->UseExternalNames = UseExternalNames;
  1678. StringMap<RedirectingFileSystem::Entry *> Entries;
  1679. for (auto &Mapping : llvm::reverse(RemappedFiles)) {
  1680. SmallString<128> From = StringRef(Mapping.first);
  1681. SmallString<128> To = StringRef(Mapping.second);
  1682. {
  1683. auto EC = ExternalFS.makeAbsolute(From);
  1684. (void)EC;
  1685. assert(!EC && "Could not make absolute path");
  1686. }
  1687. // Check if we've already mapped this file. The first one we see (in the
  1688. // reverse iteration) wins.
  1689. RedirectingFileSystem::Entry *&ToEntry = Entries[From];
  1690. if (ToEntry)
  1691. continue;
  1692. // Add parent directories.
  1693. RedirectingFileSystem::Entry *Parent = nullptr;
  1694. StringRef FromDirectory = llvm::sys::path::parent_path(From);
  1695. for (auto I = llvm::sys::path::begin(FromDirectory),
  1696. E = llvm::sys::path::end(FromDirectory);
  1697. I != E; ++I) {
  1698. Parent = RedirectingFileSystemParser::lookupOrCreateEntry(FS.get(), *I,
  1699. Parent);
  1700. }
  1701. assert(Parent && "File without a directory?");
  1702. {
  1703. auto EC = ExternalFS.makeAbsolute(To);
  1704. (void)EC;
  1705. assert(!EC && "Could not make absolute path");
  1706. }
  1707. // Add the file.
  1708. auto NewFile = std::make_unique<RedirectingFileSystem::FileEntry>(
  1709. llvm::sys::path::filename(From), To,
  1710. UseExternalNames ? RedirectingFileSystem::NK_External
  1711. : RedirectingFileSystem::NK_Virtual);
  1712. ToEntry = NewFile.get();
  1713. cast<RedirectingFileSystem::DirectoryEntry>(Parent)->addContent(
  1714. std::move(NewFile));
  1715. }
  1716. return FS;
  1717. }
  1718. RedirectingFileSystem::LookupResult::LookupResult(
  1719. Entry *E, sys::path::const_iterator Start, sys::path::const_iterator End)
  1720. : E(E) {
  1721. assert(E != nullptr);
  1722. // If the matched entry is a DirectoryRemapEntry, set ExternalRedirect to the
  1723. // path of the directory it maps to in the external file system plus any
  1724. // remaining path components in the provided iterator.
  1725. if (auto *DRE = dyn_cast<RedirectingFileSystem::DirectoryRemapEntry>(E)) {
  1726. SmallString<256> Redirect(DRE->getExternalContentsPath());
  1727. sys::path::append(Redirect, Start, End,
  1728. getExistingStyle(DRE->getExternalContentsPath()));
  1729. ExternalRedirect = std::string(Redirect);
  1730. }
  1731. }
  1732. bool RedirectingFileSystem::shouldFallBackToExternalFS(
  1733. std::error_code EC, RedirectingFileSystem::Entry *E) const {
  1734. if (E && !isa<RedirectingFileSystem::DirectoryRemapEntry>(E))
  1735. return false;
  1736. return shouldUseExternalFS() && EC == llvm::errc::no_such_file_or_directory;
  1737. }
  1738. std::error_code
  1739. RedirectingFileSystem::makeCanonical(SmallVectorImpl<char> &Path) const {
  1740. if (std::error_code EC = makeAbsolute(Path))
  1741. return EC;
  1742. llvm::SmallString<256> CanonicalPath =
  1743. canonicalize(StringRef(Path.data(), Path.size()));
  1744. if (CanonicalPath.empty())
  1745. return make_error_code(llvm::errc::invalid_argument);
  1746. Path.assign(CanonicalPath.begin(), CanonicalPath.end());
  1747. return {};
  1748. }
  1749. ErrorOr<RedirectingFileSystem::LookupResult>
  1750. RedirectingFileSystem::lookupPath(StringRef Path) const {
  1751. sys::path::const_iterator Start = sys::path::begin(Path);
  1752. sys::path::const_iterator End = sys::path::end(Path);
  1753. for (const auto &Root : Roots) {
  1754. ErrorOr<RedirectingFileSystem::LookupResult> Result =
  1755. lookupPathImpl(Start, End, Root.get());
  1756. if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
  1757. return Result;
  1758. }
  1759. return make_error_code(llvm::errc::no_such_file_or_directory);
  1760. }
  1761. ErrorOr<RedirectingFileSystem::LookupResult>
  1762. RedirectingFileSystem::lookupPathImpl(
  1763. sys::path::const_iterator Start, sys::path::const_iterator End,
  1764. RedirectingFileSystem::Entry *From) const {
  1765. assert(!isTraversalComponent(*Start) &&
  1766. !isTraversalComponent(From->getName()) &&
  1767. "Paths should not contain traversal components");
  1768. StringRef FromName = From->getName();
  1769. // Forward the search to the next component in case this is an empty one.
  1770. if (!FromName.empty()) {
  1771. if (!pathComponentMatches(*Start, FromName))
  1772. return make_error_code(llvm::errc::no_such_file_or_directory);
  1773. ++Start;
  1774. if (Start == End) {
  1775. // Match!
  1776. return LookupResult(From, Start, End);
  1777. }
  1778. }
  1779. if (isa<RedirectingFileSystem::FileEntry>(From))
  1780. return make_error_code(llvm::errc::not_a_directory);
  1781. if (isa<RedirectingFileSystem::DirectoryRemapEntry>(From))
  1782. return LookupResult(From, Start, End);
  1783. auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(From);
  1784. for (const std::unique_ptr<RedirectingFileSystem::Entry> &DirEntry :
  1785. llvm::make_range(DE->contents_begin(), DE->contents_end())) {
  1786. ErrorOr<RedirectingFileSystem::LookupResult> Result =
  1787. lookupPathImpl(Start, End, DirEntry.get());
  1788. if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
  1789. return Result;
  1790. }
  1791. return make_error_code(llvm::errc::no_such_file_or_directory);
  1792. }
  1793. static Status getRedirectedFileStatus(const Twine &OriginalPath,
  1794. bool UseExternalNames,
  1795. Status ExternalStatus) {
  1796. Status S = ExternalStatus;
  1797. if (!UseExternalNames)
  1798. S = Status::copyWithNewName(S, OriginalPath);
  1799. S.IsVFSMapped = true;
  1800. return S;
  1801. }
  1802. ErrorOr<Status> RedirectingFileSystem::status(
  1803. const Twine &CanonicalPath, const Twine &OriginalPath,
  1804. const RedirectingFileSystem::LookupResult &Result) {
  1805. if (Optional<StringRef> ExtRedirect = Result.getExternalRedirect()) {
  1806. SmallString<256> CanonicalRemappedPath((*ExtRedirect).str());
  1807. if (std::error_code EC = makeCanonical(CanonicalRemappedPath))
  1808. return EC;
  1809. ErrorOr<Status> S = ExternalFS->status(CanonicalRemappedPath);
  1810. if (!S)
  1811. return S;
  1812. S = Status::copyWithNewName(*S, *ExtRedirect);
  1813. auto *RE = cast<RedirectingFileSystem::RemapEntry>(Result.E);
  1814. return getRedirectedFileStatus(OriginalPath,
  1815. RE->useExternalName(UseExternalNames), *S);
  1816. }
  1817. auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(Result.E);
  1818. return Status::copyWithNewName(DE->getStatus(), CanonicalPath);
  1819. }
  1820. ErrorOr<Status>
  1821. RedirectingFileSystem::getExternalStatus(const Twine &CanonicalPath,
  1822. const Twine &OriginalPath) const {
  1823. if (auto Result = ExternalFS->status(CanonicalPath)) {
  1824. return Result.get().copyWithNewName(Result.get(), OriginalPath);
  1825. } else {
  1826. return Result.getError();
  1827. }
  1828. }
  1829. ErrorOr<Status> RedirectingFileSystem::status(const Twine &OriginalPath) {
  1830. SmallString<256> CanonicalPath;
  1831. OriginalPath.toVector(CanonicalPath);
  1832. if (std::error_code EC = makeCanonical(CanonicalPath))
  1833. return EC;
  1834. ErrorOr<RedirectingFileSystem::LookupResult> Result =
  1835. lookupPath(CanonicalPath);
  1836. if (!Result) {
  1837. if (shouldFallBackToExternalFS(Result.getError())) {
  1838. return getExternalStatus(CanonicalPath, OriginalPath);
  1839. }
  1840. return Result.getError();
  1841. }
  1842. ErrorOr<Status> S = status(CanonicalPath, OriginalPath, *Result);
  1843. if (!S && shouldFallBackToExternalFS(S.getError(), Result->E)) {
  1844. return getExternalStatus(CanonicalPath, OriginalPath);
  1845. }
  1846. return S;
  1847. }
  1848. namespace {
  1849. /// Provide a file wrapper with an overriden status.
  1850. class FileWithFixedStatus : public File {
  1851. std::unique_ptr<File> InnerFile;
  1852. Status S;
  1853. public:
  1854. FileWithFixedStatus(std::unique_ptr<File> InnerFile, Status S)
  1855. : InnerFile(std::move(InnerFile)), S(std::move(S)) {}
  1856. ErrorOr<Status> status() override { return S; }
  1857. ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
  1858. getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
  1859. bool IsVolatile) override {
  1860. return InnerFile->getBuffer(Name, FileSize, RequiresNullTerminator,
  1861. IsVolatile);
  1862. }
  1863. std::error_code close() override { return InnerFile->close(); }
  1864. void setPath(const Twine &Path) override { S = S.copyWithNewName(S, Path); }
  1865. };
  1866. } // namespace
  1867. ErrorOr<std::unique_ptr<File>>
  1868. File::getWithPath(ErrorOr<std::unique_ptr<File>> Result, const Twine &P) {
  1869. if (!Result)
  1870. return Result;
  1871. ErrorOr<std::unique_ptr<File>> F = std::move(*Result);
  1872. auto Name = F->get()->getName();
  1873. if (Name && Name.get() != P.str())
  1874. F->get()->setPath(P);
  1875. return F;
  1876. }
  1877. ErrorOr<std::unique_ptr<File>>
  1878. RedirectingFileSystem::openFileForRead(const Twine &OriginalPath) {
  1879. SmallString<256> CanonicalPath;
  1880. OriginalPath.toVector(CanonicalPath);
  1881. if (std::error_code EC = makeCanonical(CanonicalPath))
  1882. return EC;
  1883. ErrorOr<RedirectingFileSystem::LookupResult> Result =
  1884. lookupPath(CanonicalPath);
  1885. if (!Result) {
  1886. if (shouldFallBackToExternalFS(Result.getError()))
  1887. return File::getWithPath(ExternalFS->openFileForRead(CanonicalPath),
  1888. OriginalPath);
  1889. return Result.getError();
  1890. }
  1891. if (!Result->getExternalRedirect()) // FIXME: errc::not_a_file?
  1892. return make_error_code(llvm::errc::invalid_argument);
  1893. StringRef ExtRedirect = *Result->getExternalRedirect();
  1894. SmallString<256> CanonicalRemappedPath(ExtRedirect.str());
  1895. if (std::error_code EC = makeCanonical(CanonicalRemappedPath))
  1896. return EC;
  1897. auto *RE = cast<RedirectingFileSystem::RemapEntry>(Result->E);
  1898. auto ExternalFile = File::getWithPath(
  1899. ExternalFS->openFileForRead(CanonicalRemappedPath), ExtRedirect);
  1900. if (!ExternalFile) {
  1901. if (shouldFallBackToExternalFS(ExternalFile.getError(), Result->E))
  1902. return File::getWithPath(ExternalFS->openFileForRead(CanonicalPath),
  1903. OriginalPath);
  1904. return ExternalFile;
  1905. }
  1906. auto ExternalStatus = (*ExternalFile)->status();
  1907. if (!ExternalStatus)
  1908. return ExternalStatus.getError();
  1909. // FIXME: Update the status with the name and VFSMapped.
  1910. Status S = getRedirectedFileStatus(
  1911. OriginalPath, RE->useExternalName(UseExternalNames), *ExternalStatus);
  1912. return std::unique_ptr<File>(
  1913. std::make_unique<FileWithFixedStatus>(std::move(*ExternalFile), S));
  1914. }
  1915. std::error_code
  1916. RedirectingFileSystem::getRealPath(const Twine &Path_,
  1917. SmallVectorImpl<char> &Output) const {
  1918. SmallString<256> Path;
  1919. Path_.toVector(Path);
  1920. if (std::error_code EC = makeCanonical(Path))
  1921. return EC;
  1922. ErrorOr<RedirectingFileSystem::LookupResult> Result = lookupPath(Path);
  1923. if (!Result) {
  1924. if (shouldFallBackToExternalFS(Result.getError()))
  1925. return ExternalFS->getRealPath(Path, Output);
  1926. return Result.getError();
  1927. }
  1928. // If we found FileEntry or DirectoryRemapEntry, look up the mapped
  1929. // path in the external file system.
  1930. if (auto ExtRedirect = Result->getExternalRedirect()) {
  1931. auto P = ExternalFS->getRealPath(*ExtRedirect, Output);
  1932. if (!P && shouldFallBackToExternalFS(P, Result->E)) {
  1933. return ExternalFS->getRealPath(Path, Output);
  1934. }
  1935. return P;
  1936. }
  1937. // If we found a DirectoryEntry, still fall back to ExternalFS if allowed,
  1938. // because directories don't have a single external contents path.
  1939. return shouldUseExternalFS() ? ExternalFS->getRealPath(Path, Output)
  1940. : llvm::errc::invalid_argument;
  1941. }
  1942. std::unique_ptr<FileSystem>
  1943. vfs::getVFSFromYAML(std::unique_ptr<MemoryBuffer> Buffer,
  1944. SourceMgr::DiagHandlerTy DiagHandler,
  1945. StringRef YAMLFilePath, void *DiagContext,
  1946. IntrusiveRefCntPtr<FileSystem> ExternalFS) {
  1947. return RedirectingFileSystem::create(std::move(Buffer), DiagHandler,
  1948. YAMLFilePath, DiagContext,
  1949. std::move(ExternalFS));
  1950. }
  1951. static void getVFSEntries(RedirectingFileSystem::Entry *SrcE,
  1952. SmallVectorImpl<StringRef> &Path,
  1953. SmallVectorImpl<YAMLVFSEntry> &Entries) {
  1954. auto Kind = SrcE->getKind();
  1955. if (Kind == RedirectingFileSystem::EK_Directory) {
  1956. auto *DE = dyn_cast<RedirectingFileSystem::DirectoryEntry>(SrcE);
  1957. assert(DE && "Must be a directory");
  1958. for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
  1959. llvm::make_range(DE->contents_begin(), DE->contents_end())) {
  1960. Path.push_back(SubEntry->getName());
  1961. getVFSEntries(SubEntry.get(), Path, Entries);
  1962. Path.pop_back();
  1963. }
  1964. return;
  1965. }
  1966. if (Kind == RedirectingFileSystem::EK_DirectoryRemap) {
  1967. auto *DR = dyn_cast<RedirectingFileSystem::DirectoryRemapEntry>(SrcE);
  1968. assert(DR && "Must be a directory remap");
  1969. SmallString<128> VPath;
  1970. for (auto &Comp : Path)
  1971. llvm::sys::path::append(VPath, Comp);
  1972. Entries.push_back(
  1973. YAMLVFSEntry(VPath.c_str(), DR->getExternalContentsPath()));
  1974. return;
  1975. }
  1976. assert(Kind == RedirectingFileSystem::EK_File && "Must be a EK_File");
  1977. auto *FE = dyn_cast<RedirectingFileSystem::FileEntry>(SrcE);
  1978. assert(FE && "Must be a file");
  1979. SmallString<128> VPath;
  1980. for (auto &Comp : Path)
  1981. llvm::sys::path::append(VPath, Comp);
  1982. Entries.push_back(YAMLVFSEntry(VPath.c_str(), FE->getExternalContentsPath()));
  1983. }
  1984. void vfs::collectVFSFromYAML(std::unique_ptr<MemoryBuffer> Buffer,
  1985. SourceMgr::DiagHandlerTy DiagHandler,
  1986. StringRef YAMLFilePath,
  1987. SmallVectorImpl<YAMLVFSEntry> &CollectedEntries,
  1988. void *DiagContext,
  1989. IntrusiveRefCntPtr<FileSystem> ExternalFS) {
  1990. std::unique_ptr<RedirectingFileSystem> VFS = RedirectingFileSystem::create(
  1991. std::move(Buffer), DiagHandler, YAMLFilePath, DiagContext,
  1992. std::move(ExternalFS));
  1993. if (!VFS)
  1994. return;
  1995. ErrorOr<RedirectingFileSystem::LookupResult> RootResult =
  1996. VFS->lookupPath("/");
  1997. if (!RootResult)
  1998. return;
  1999. SmallVector<StringRef, 8> Components;
  2000. Components.push_back("/");
  2001. getVFSEntries(RootResult->E, Components, CollectedEntries);
  2002. }
  2003. UniqueID vfs::getNextVirtualUniqueID() {
  2004. static std::atomic<unsigned> UID;
  2005. unsigned ID = ++UID;
  2006. // The following assumes that uint64_t max will never collide with a real
  2007. // dev_t value from the OS.
  2008. return UniqueID(std::numeric_limits<uint64_t>::max(), ID);
  2009. }
  2010. void YAMLVFSWriter::addEntry(StringRef VirtualPath, StringRef RealPath,
  2011. bool IsDirectory) {
  2012. assert(sys::path::is_absolute(VirtualPath) && "virtual path not absolute");
  2013. assert(sys::path::is_absolute(RealPath) && "real path not absolute");
  2014. assert(!pathHasTraversal(VirtualPath) && "path traversal is not supported");
  2015. Mappings.emplace_back(VirtualPath, RealPath, IsDirectory);
  2016. }
  2017. void YAMLVFSWriter::addFileMapping(StringRef VirtualPath, StringRef RealPath) {
  2018. addEntry(VirtualPath, RealPath, /*IsDirectory=*/false);
  2019. }
  2020. void YAMLVFSWriter::addDirectoryMapping(StringRef VirtualPath,
  2021. StringRef RealPath) {
  2022. addEntry(VirtualPath, RealPath, /*IsDirectory=*/true);
  2023. }
  2024. namespace {
  2025. class JSONWriter {
  2026. llvm::raw_ostream &OS;
  2027. SmallVector<StringRef, 16> DirStack;
  2028. unsigned getDirIndent() { return 4 * DirStack.size(); }
  2029. unsigned getFileIndent() { return 4 * (DirStack.size() + 1); }
  2030. bool containedIn(StringRef Parent, StringRef Path);
  2031. StringRef containedPart(StringRef Parent, StringRef Path);
  2032. void startDirectory(StringRef Path);
  2033. void endDirectory();
  2034. void writeEntry(StringRef VPath, StringRef RPath);
  2035. public:
  2036. JSONWriter(llvm::raw_ostream &OS) : OS(OS) {}
  2037. void write(ArrayRef<YAMLVFSEntry> Entries, Optional<bool> UseExternalNames,
  2038. Optional<bool> IsCaseSensitive, Optional<bool> IsOverlayRelative,
  2039. StringRef OverlayDir);
  2040. };
  2041. } // namespace
  2042. bool JSONWriter::containedIn(StringRef Parent, StringRef Path) {
  2043. using namespace llvm::sys;
  2044. // Compare each path component.
  2045. auto IParent = path::begin(Parent), EParent = path::end(Parent);
  2046. for (auto IChild = path::begin(Path), EChild = path::end(Path);
  2047. IParent != EParent && IChild != EChild; ++IParent, ++IChild) {
  2048. if (*IParent != *IChild)
  2049. return false;
  2050. }
  2051. // Have we exhausted the parent path?
  2052. return IParent == EParent;
  2053. }
  2054. StringRef JSONWriter::containedPart(StringRef Parent, StringRef Path) {
  2055. assert(!Parent.empty());
  2056. assert(containedIn(Parent, Path));
  2057. return Path.slice(Parent.size() + 1, StringRef::npos);
  2058. }
  2059. void JSONWriter::startDirectory(StringRef Path) {
  2060. StringRef Name =
  2061. DirStack.empty() ? Path : containedPart(DirStack.back(), Path);
  2062. DirStack.push_back(Path);
  2063. unsigned Indent = getDirIndent();
  2064. OS.indent(Indent) << "{\n";
  2065. OS.indent(Indent + 2) << "'type': 'directory',\n";
  2066. OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(Name) << "\",\n";
  2067. OS.indent(Indent + 2) << "'contents': [\n";
  2068. }
  2069. void JSONWriter::endDirectory() {
  2070. unsigned Indent = getDirIndent();
  2071. OS.indent(Indent + 2) << "]\n";
  2072. OS.indent(Indent) << "}";
  2073. DirStack.pop_back();
  2074. }
  2075. void JSONWriter::writeEntry(StringRef VPath, StringRef RPath) {
  2076. unsigned Indent = getFileIndent();
  2077. OS.indent(Indent) << "{\n";
  2078. OS.indent(Indent + 2) << "'type': 'file',\n";
  2079. OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(VPath) << "\",\n";
  2080. OS.indent(Indent + 2) << "'external-contents': \""
  2081. << llvm::yaml::escape(RPath) << "\"\n";
  2082. OS.indent(Indent) << "}";
  2083. }
  2084. void JSONWriter::write(ArrayRef<YAMLVFSEntry> Entries,
  2085. Optional<bool> UseExternalNames,
  2086. Optional<bool> IsCaseSensitive,
  2087. Optional<bool> IsOverlayRelative,
  2088. StringRef OverlayDir) {
  2089. using namespace llvm::sys;
  2090. OS << "{\n"
  2091. " 'version': 0,\n";
  2092. if (IsCaseSensitive.hasValue())
  2093. OS << " 'case-sensitive': '"
  2094. << (IsCaseSensitive.getValue() ? "true" : "false") << "',\n";
  2095. if (UseExternalNames.hasValue())
  2096. OS << " 'use-external-names': '"
  2097. << (UseExternalNames.getValue() ? "true" : "false") << "',\n";
  2098. bool UseOverlayRelative = false;
  2099. if (IsOverlayRelative.hasValue()) {
  2100. UseOverlayRelative = IsOverlayRelative.getValue();
  2101. OS << " 'overlay-relative': '" << (UseOverlayRelative ? "true" : "false")
  2102. << "',\n";
  2103. }
  2104. OS << " 'roots': [\n";
  2105. if (!Entries.empty()) {
  2106. const YAMLVFSEntry &Entry = Entries.front();
  2107. startDirectory(
  2108. Entry.IsDirectory ? Entry.VPath : path::parent_path(Entry.VPath)
  2109. );
  2110. StringRef RPath = Entry.RPath;
  2111. if (UseOverlayRelative) {
  2112. unsigned OverlayDirLen = OverlayDir.size();
  2113. assert(RPath.substr(0, OverlayDirLen) == OverlayDir &&
  2114. "Overlay dir must be contained in RPath");
  2115. RPath = RPath.slice(OverlayDirLen, RPath.size());
  2116. }
  2117. bool IsCurrentDirEmpty = true;
  2118. if (!Entry.IsDirectory) {
  2119. writeEntry(path::filename(Entry.VPath), RPath);
  2120. IsCurrentDirEmpty = false;
  2121. }
  2122. for (const auto &Entry : Entries.slice(1)) {
  2123. StringRef Dir =
  2124. Entry.IsDirectory ? Entry.VPath : path::parent_path(Entry.VPath);
  2125. if (Dir == DirStack.back()) {
  2126. if (!IsCurrentDirEmpty) {
  2127. OS << ",\n";
  2128. }
  2129. } else {
  2130. bool IsDirPoppedFromStack = false;
  2131. while (!DirStack.empty() && !containedIn(DirStack.back(), Dir)) {
  2132. OS << "\n";
  2133. endDirectory();
  2134. IsDirPoppedFromStack = true;
  2135. }
  2136. if (IsDirPoppedFromStack || !IsCurrentDirEmpty) {
  2137. OS << ",\n";
  2138. }
  2139. startDirectory(Dir);
  2140. IsCurrentDirEmpty = true;
  2141. }
  2142. StringRef RPath = Entry.RPath;
  2143. if (UseOverlayRelative) {
  2144. unsigned OverlayDirLen = OverlayDir.size();
  2145. assert(RPath.substr(0, OverlayDirLen) == OverlayDir &&
  2146. "Overlay dir must be contained in RPath");
  2147. RPath = RPath.slice(OverlayDirLen, RPath.size());
  2148. }
  2149. if (!Entry.IsDirectory) {
  2150. writeEntry(path::filename(Entry.VPath), RPath);
  2151. IsCurrentDirEmpty = false;
  2152. }
  2153. }
  2154. while (!DirStack.empty()) {
  2155. OS << "\n";
  2156. endDirectory();
  2157. }
  2158. OS << "\n";
  2159. }
  2160. OS << " ]\n"
  2161. << "}\n";
  2162. }
  2163. void YAMLVFSWriter::write(llvm::raw_ostream &OS) {
  2164. llvm::sort(Mappings, [](const YAMLVFSEntry &LHS, const YAMLVFSEntry &RHS) {
  2165. return LHS.VPath < RHS.VPath;
  2166. });
  2167. JSONWriter(OS).write(Mappings, UseExternalNames, IsCaseSensitive,
  2168. IsOverlayRelative, OverlayDir);
  2169. }
  2170. vfs::recursive_directory_iterator::recursive_directory_iterator(
  2171. FileSystem &FS_, const Twine &Path, std::error_code &EC)
  2172. : FS(&FS_) {
  2173. directory_iterator I = FS->dir_begin(Path, EC);
  2174. if (I != directory_iterator()) {
  2175. State = std::make_shared<detail::RecDirIterState>();
  2176. State->Stack.push(I);
  2177. }
  2178. }
  2179. vfs::recursive_directory_iterator &
  2180. recursive_directory_iterator::increment(std::error_code &EC) {
  2181. assert(FS && State && !State->Stack.empty() && "incrementing past end");
  2182. assert(!State->Stack.top()->path().empty() && "non-canonical end iterator");
  2183. vfs::directory_iterator End;
  2184. if (State->HasNoPushRequest)
  2185. State->HasNoPushRequest = false;
  2186. else {
  2187. if (State->Stack.top()->type() == sys::fs::file_type::directory_file) {
  2188. vfs::directory_iterator I = FS->dir_begin(State->Stack.top()->path(), EC);
  2189. if (I != End) {
  2190. State->Stack.push(I);
  2191. return *this;
  2192. }
  2193. }
  2194. }
  2195. while (!State->Stack.empty() && State->Stack.top().increment(EC) == End)
  2196. State->Stack.pop();
  2197. if (State->Stack.empty())
  2198. State.reset(); // end iterator
  2199. return *this;
  2200. }