Skip to content

Commit 5681311

Browse files
committed
[VFS] Move RedirectingFileSystem interface into header (NFC)
This moves the RedirectingFileSystem into the header so it can be extended. This is needed in LLDB we need a way to obtain the external path to deal with FILE* and file descriptor APIs. Discussion on the mailing list: http://lists.llvm.org/pipermail/llvm-dev/2018-November/127755.html Differential revision: https://reviews.llvm.org/D54277 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@351265 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 2e3d9f7 commit 5681311

File tree

2 files changed

+391
-339
lines changed

2 files changed

+391
-339
lines changed

include/llvm/Support/VirtualFileSystem.h

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "llvm/Support/Chrono.h"
2525
#include "llvm/Support/ErrorOr.h"
2626
#include "llvm/Support/FileSystem.h"
27+
#include "llvm/Support/Path.h"
2728
#include "llvm/Support/SourceMgr.h"
2829
#include <cassert>
2930
#include <cstdint>
@@ -495,6 +496,230 @@ struct YAMLVFSEntry {
495496
std::string RPath;
496497
};
497498

499+
class VFSFromYamlDirIterImpl;
500+
class RedirectingFileSystemParser;
501+
502+
/// A virtual file system parsed from a YAML file.
503+
///
504+
/// Currently, this class allows creating virtual directories and mapping
505+
/// virtual file paths to existing external files, available in \c ExternalFS.
506+
///
507+
/// The basic structure of the parsed file is:
508+
/// \verbatim
509+
/// {
510+
/// 'version': <version number>,
511+
/// <optional configuration>
512+
/// 'roots': [
513+
/// <directory entries>
514+
/// ]
515+
/// }
516+
/// \endverbatim
517+
///
518+
/// All configuration options are optional.
519+
/// 'case-sensitive': <boolean, default=true>
520+
/// 'use-external-names': <boolean, default=true>
521+
/// 'overlay-relative': <boolean, default=false>
522+
/// 'fallthrough': <boolean, default=true>
523+
///
524+
/// Virtual directories are represented as
525+
/// \verbatim
526+
/// {
527+
/// 'type': 'directory',
528+
/// 'name': <string>,
529+
/// 'contents': [ <file or directory entries> ]
530+
/// }
531+
/// \endverbatim
532+
///
533+
/// The default attributes for virtual directories are:
534+
/// \verbatim
535+
/// MTime = now() when created
536+
/// Perms = 0777
537+
/// User = Group = 0
538+
/// Size = 0
539+
/// UniqueID = unspecified unique value
540+
/// \endverbatim
541+
///
542+
/// Re-mapped files are represented as
543+
/// \verbatim
544+
/// {
545+
/// 'type': 'file',
546+
/// 'name': <string>,
547+
/// 'use-external-name': <boolean> # Optional
548+
/// 'external-contents': <path to external file>
549+
/// }
550+
/// \endverbatim
551+
///
552+
/// and inherit their attributes from the external contents.
553+
///
554+
/// In both cases, the 'name' field may contain multiple path components (e.g.
555+
/// /path/to/file). However, any directory that contains more than one child
556+
/// must be uniquely represented by a directory entry.
557+
class RedirectingFileSystem : public vfs::FileSystem {
558+
public:
559+
enum EntryKind { EK_Directory, EK_File };
560+
561+
/// A single file or directory in the VFS.
562+
class Entry {
563+
EntryKind Kind;
564+
std::string Name;
565+
566+
public:
567+
Entry(EntryKind K, StringRef Name) : Kind(K), Name(Name) {}
568+
virtual ~Entry() = default;
569+
570+
StringRef getName() const { return Name; }
571+
EntryKind getKind() const { return Kind; }
572+
};
573+
574+
class RedirectingDirectoryEntry : public Entry {
575+
std::vector<std::unique_ptr<Entry>> Contents;
576+
Status S;
577+
578+
public:
579+
RedirectingDirectoryEntry(StringRef Name,
580+
std::vector<std::unique_ptr<Entry>> Contents,
581+
Status S)
582+
: Entry(EK_Directory, Name), Contents(std::move(Contents)),
583+
S(std::move(S)) {}
584+
RedirectingDirectoryEntry(StringRef Name, Status S)
585+
: Entry(EK_Directory, Name), S(std::move(S)) {}
586+
587+
Status getStatus() { return S; }
588+
589+
void addContent(std::unique_ptr<Entry> Content) {
590+
Contents.push_back(std::move(Content));
591+
}
592+
593+
Entry *getLastContent() const { return Contents.back().get(); }
594+
595+
using iterator = decltype(Contents)::iterator;
596+
597+
iterator contents_begin() { return Contents.begin(); }
598+
iterator contents_end() { return Contents.end(); }
599+
600+
static bool classof(const Entry *E) { return E->getKind() == EK_Directory; }
601+
};
602+
603+
class RedirectingFileEntry : public Entry {
604+
public:
605+
enum NameKind { NK_NotSet, NK_External, NK_Virtual };
606+
607+
private:
608+
std::string ExternalContentsPath;
609+
NameKind UseName;
610+
611+
public:
612+
RedirectingFileEntry(StringRef Name, StringRef ExternalContentsPath,
613+
NameKind UseName)
614+
: Entry(EK_File, Name), ExternalContentsPath(ExternalContentsPath),
615+
UseName(UseName) {}
616+
617+
StringRef getExternalContentsPath() const { return ExternalContentsPath; }
618+
619+
/// whether to use the external path as the name for this file.
620+
bool useExternalName(bool GlobalUseExternalName) const {
621+
return UseName == NK_NotSet ? GlobalUseExternalName
622+
: (UseName == NK_External);
623+
}
624+
625+
NameKind getUseName() const { return UseName; }
626+
627+
static bool classof(const Entry *E) { return E->getKind() == EK_File; }
628+
};
629+
630+
private:
631+
friend class VFSFromYamlDirIterImpl;
632+
friend class RedirectingFileSystemParser;
633+
634+
/// The root(s) of the virtual file system.
635+
std::vector<std::unique_ptr<Entry>> Roots;
636+
637+
/// The file system to use for external references.
638+
IntrusiveRefCntPtr<FileSystem> ExternalFS;
639+
640+
/// If IsRelativeOverlay is set, this represents the directory
641+
/// path that should be prefixed to each 'external-contents' entry
642+
/// when reading from YAML files.
643+
std::string ExternalContentsPrefixDir;
644+
645+
/// @name Configuration
646+
/// @{
647+
648+
/// Whether to perform case-sensitive comparisons.
649+
///
650+
/// Currently, case-insensitive matching only works correctly with ASCII.
651+
bool CaseSensitive = true;
652+
653+
/// IsRelativeOverlay marks whether a ExternalContentsPrefixDir path must
654+
/// be prefixed in every 'external-contents' when reading from YAML files.
655+
bool IsRelativeOverlay = false;
656+
657+
/// Whether to use to use the value of 'external-contents' for the
658+
/// names of files. This global value is overridable on a per-file basis.
659+
bool UseExternalNames = true;
660+
661+
/// Whether to attempt a file lookup in external file system after it wasn't
662+
/// found in VFS.
663+
bool IsFallthrough = true;
664+
/// @}
665+
666+
/// Virtual file paths and external files could be canonicalized without "..",
667+
/// "." and "./" in their paths. FIXME: some unittests currently fail on
668+
/// win32 when using remove_dots and remove_leading_dotslash on paths.
669+
bool UseCanonicalizedPaths =
670+
#ifdef _WIN32
671+
false;
672+
#else
673+
true;
674+
#endif
675+
676+
RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> ExternalFS)
677+
: ExternalFS(std::move(ExternalFS)) {}
678+
679+
/// Looks up the path <tt>[Start, End)</tt> in \p From, possibly
680+
/// recursing into the contents of \p From if it is a directory.
681+
ErrorOr<Entry *> lookupPath(llvm::sys::path::const_iterator Start,
682+
llvm::sys::path::const_iterator End,
683+
Entry *From) const;
684+
685+
/// Get the status of a given an \c Entry.
686+
ErrorOr<Status> status(const Twine &Path, Entry *E);
687+
688+
public:
689+
/// Looks up \p Path in \c Roots.
690+
ErrorOr<Entry *> lookupPath(const Twine &Path) const;
691+
692+
/// Parses \p Buffer, which is expected to be in YAML format and
693+
/// returns a virtual file system representing its contents.
694+
static RedirectingFileSystem *
695+
create(std::unique_ptr<MemoryBuffer> Buffer,
696+
SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath,
697+
void *DiagContext, IntrusiveRefCntPtr<FileSystem> ExternalFS);
698+
699+
ErrorOr<Status> status(const Twine &Path) override;
700+
ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override;
701+
702+
std::error_code getRealPath(const Twine &Path,
703+
SmallVectorImpl<char> &Output) const override;
704+
705+
llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override;
706+
707+
std::error_code setCurrentWorkingDirectory(const Twine &Path) override;
708+
709+
std::error_code isLocal(const Twine &Path, bool &Result) override;
710+
711+
directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
712+
713+
void setExternalContentsPrefixDir(StringRef PrefixDir);
714+
715+
StringRef getExternalContentsPrefixDir() const;
716+
717+
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
718+
LLVM_DUMP_METHOD void dump() const;
719+
LLVM_DUMP_METHOD void dumpEntry(Entry *E, int NumSpaces = 0) const;
720+
#endif
721+
};
722+
498723
/// Collect all pairs of <virtual path, real path> entries from the
499724
/// \p YAMLFilePath. This is used by the module dependency collector to forward
500725
/// the entries into the reproducer output VFS YAML file.

0 commit comments

Comments
 (0)