VirtualFileSystem.cpp 100 KB

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