2018-03-28 22:09:09 +00:00
|
|
|
//===- VirtualFileSystem.cpp - Virtual File System Layer ------------------===//
|
2014-02-20 21:59:23 +00:00
|
|
|
//
|
2019-01-19 08:50:56 +00:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2014-02-20 21:59:23 +00:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
2018-03-28 22:09:09 +00:00
|
|
|
//
|
2014-02-20 21:59:23 +00:00
|
|
|
// This file implements the VirtualFileSystem interface.
|
2018-03-28 22:09:09 +00:00
|
|
|
//
|
2014-02-20 21:59:23 +00:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2018-10-10 13:27:25 +00:00
|
|
|
#include "llvm/Support/VirtualFileSystem.h"
|
2018-03-28 22:09:09 +00:00
|
|
|
#include "llvm/ADT/ArrayRef.h"
|
2014-02-21 23:39:37 +00:00
|
|
|
#include "llvm/ADT/DenseMap.h"
|
2018-03-28 22:09:09 +00:00
|
|
|
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
2014-02-21 23:39:37 +00:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2018-03-28 22:09:09 +00:00
|
|
|
#include "llvm/ADT/SmallString.h"
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
|
|
|
#include "llvm/ADT/StringRef.h"
|
2014-06-24 19:37:16 +00:00
|
|
|
#include "llvm/ADT/StringSet.h"
|
2018-03-28 22:09:09 +00:00
|
|
|
#include "llvm/ADT/Twine.h"
|
2015-01-14 11:29:14 +00:00
|
|
|
#include "llvm/ADT/iterator_range.h"
|
2016-05-27 14:27:13 +00:00
|
|
|
#include "llvm/Config/llvm-config.h"
|
2018-03-28 22:09:09 +00:00
|
|
|
#include "llvm/Support/Casting.h"
|
|
|
|
#include "llvm/Support/Chrono.h"
|
2018-09-04 14:15:53 +00:00
|
|
|
#include "llvm/Support/Compiler.h"
|
2016-05-06 23:21:57 +00:00
|
|
|
#include "llvm/Support/Debug.h"
|
2014-06-13 17:20:50 +00:00
|
|
|
#include "llvm/Support/Errc.h"
|
2018-03-28 22:09:09 +00:00
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
|
|
#include "llvm/Support/ErrorOr.h"
|
|
|
|
#include "llvm/Support/FileSystem.h"
|
2021-09-29 15:25:15 +02:00
|
|
|
#include "llvm/Support/FileSystem/UniqueID.h"
|
2014-02-20 21:59:23 +00:00
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
|
|
#include "llvm/Support/Path.h"
|
2018-03-28 22:09:09 +00:00
|
|
|
#include "llvm/Support/SMLoc.h"
|
|
|
|
#include "llvm/Support/SourceMgr.h"
|
2014-02-21 23:39:37 +00:00
|
|
|
#include "llvm/Support/YAMLParser.h"
|
2018-03-28 22:09:09 +00:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
#include <algorithm>
|
2014-03-02 17:08:31 +00:00
|
|
|
#include <atomic>
|
2018-03-28 22:09:09 +00:00
|
|
|
#include <cassert>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <iterator>
|
|
|
|
#include <limits>
|
2023-07-19 22:25:40 -07:00
|
|
|
#include <map>
|
2014-03-09 11:36:40 +00:00
|
|
|
#include <memory>
|
2022-11-25 21:53:00 -08:00
|
|
|
#include <optional>
|
2018-03-28 22:09:09 +00:00
|
|
|
#include <string>
|
|
|
|
#include <system_error>
|
2016-05-27 14:27:13 +00:00
|
|
|
#include <utility>
|
2018-03-28 22:09:09 +00:00
|
|
|
#include <vector>
|
2014-02-20 21:59:23 +00:00
|
|
|
|
|
|
|
using namespace llvm;
|
2018-10-10 13:27:25 +00:00
|
|
|
using namespace llvm::vfs;
|
2018-03-28 22:09:09 +00:00
|
|
|
|
[Support] Move llvm::MemoryBuffer to sys::fs::file_t
Summary:
On Windows, Posix integer file descriptors are a compatibility layer
over native file handles provided by the C runtime. There is a hard
limit on the maximum number of file descriptors that a process can open,
and the limit is 8192. LLD typically doesn't run into this limit because
it opens input files, maps them into memory, and then immediately closes
the file descriptor. This prevents it from running out of FDs.
For various reasons, I'd like to open handles to every input file and
keep them open during linking. That requires migrating MemoryBuffer over
to taking open native file handles instead of integer FDs.
Reviewers: aganea, Bigcheese
Reviewed By: aganea
Subscribers: smeenai, silvas, mehdi_amini, hiraditya, steven_wu, dexonsmith, dang, llvm-commits, zturner
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63453
llvm-svn: 365588
2019-07-10 00:34:13 +00:00
|
|
|
using llvm::sys::fs::file_t;
|
2014-02-20 21:59:23 +00:00
|
|
|
using llvm::sys::fs::file_status;
|
|
|
|
using llvm::sys::fs::file_type;
|
[Support] Move llvm::MemoryBuffer to sys::fs::file_t
Summary:
On Windows, Posix integer file descriptors are a compatibility layer
over native file handles provided by the C runtime. There is a hard
limit on the maximum number of file descriptors that a process can open,
and the limit is 8192. LLD typically doesn't run into this limit because
it opens input files, maps them into memory, and then immediately closes
the file descriptor. This prevents it from running out of FDs.
For various reasons, I'd like to open handles to every input file and
keep them open during linking. That requires migrating MemoryBuffer over
to taking open native file handles instead of integer FDs.
Reviewers: aganea, Bigcheese
Reviewed By: aganea
Subscribers: smeenai, silvas, mehdi_amini, hiraditya, steven_wu, dexonsmith, dang, llvm-commits, zturner
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63453
llvm-svn: 365588
2019-07-10 00:34:13 +00:00
|
|
|
using llvm::sys::fs::kInvalidFile;
|
2014-02-20 21:59:23 +00:00
|
|
|
using llvm::sys::fs::perms;
|
|
|
|
using llvm::sys::fs::UniqueID;
|
|
|
|
|
|
|
|
Status::Status(const file_status &Status)
|
|
|
|
: UID(Status.getUniqueID()), MTime(Status.getLastModificationTime()),
|
|
|
|
User(Status.getUser()), Group(Status.getGroup()), Size(Status.getSize()),
|
2018-10-10 13:27:25 +00:00
|
|
|
Type(Status.type()), Perms(Status.permissions()) {}
|
2014-02-20 21:59:23 +00:00
|
|
|
|
2019-02-23 23:48:47 +00:00
|
|
|
Status::Status(const Twine &Name, UniqueID UID, sys::TimePoint<> MTime,
|
2015-10-05 13:15:33 +00:00
|
|
|
uint32_t User, uint32_t Group, uint64_t Size, file_type Type,
|
|
|
|
perms Perms)
|
2019-02-23 23:48:47 +00:00
|
|
|
: Name(Name.str()), UID(UID), MTime(MTime), User(User), Group(Group),
|
|
|
|
Size(Size), Type(Type), Perms(Perms) {}
|
2014-02-20 21:59:23 +00:00
|
|
|
|
2021-12-16 09:27:12 +01:00
|
|
|
Status Status::copyWithNewSize(const Status &In, uint64_t NewSize) {
|
|
|
|
return Status(In.getName(), In.getUniqueID(), In.getLastModificationTime(),
|
|
|
|
In.getUser(), In.getGroup(), NewSize, In.getType(),
|
|
|
|
In.getPermissions());
|
|
|
|
}
|
|
|
|
|
2019-02-23 23:48:47 +00:00
|
|
|
Status Status::copyWithNewName(const Status &In, const Twine &NewName) {
|
2018-07-24 20:28:07 +00:00
|
|
|
return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),
|
|
|
|
In.getUser(), In.getGroup(), In.getSize(), In.getType(),
|
|
|
|
In.getPermissions());
|
|
|
|
}
|
|
|
|
|
2019-02-23 23:48:47 +00:00
|
|
|
Status Status::copyWithNewName(const file_status &In, const Twine &NewName) {
|
2018-07-24 20:28:07 +00:00
|
|
|
return Status(NewName, In.getUniqueID(), In.getLastModificationTime(),
|
|
|
|
In.getUser(), In.getGroup(), In.getSize(), In.type(),
|
|
|
|
In.permissions());
|
2015-10-05 13:15:33 +00:00
|
|
|
}
|
|
|
|
|
2014-02-20 21:59:23 +00:00
|
|
|
bool Status::equivalent(const Status &Other) const {
|
2017-07-20 11:57:02 +00:00
|
|
|
assert(isStatusKnown() && Other.isStatusKnown());
|
2014-02-20 21:59:23 +00:00
|
|
|
return getUniqueID() == Other.getUniqueID();
|
|
|
|
}
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2018-10-10 13:27:25 +00:00
|
|
|
bool Status::isDirectory() const { return Type == file_type::directory_file; }
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2018-10-10 13:27:25 +00:00
|
|
|
bool Status::isRegularFile() const { return Type == file_type::regular_file; }
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2014-02-20 21:59:23 +00:00
|
|
|
bool Status::isOther() const {
|
|
|
|
return exists() && !isRegularFile() && !isDirectory() && !isSymlink();
|
|
|
|
}
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2018-10-10 13:27:25 +00:00
|
|
|
bool Status::isSymlink() const { return Type == file_type::symlink_file; }
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2018-10-10 13:27:25 +00:00
|
|
|
bool Status::isStatusKnown() const { return Type != file_type::status_error; }
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2014-02-20 21:59:23 +00:00
|
|
|
bool Status::exists() const {
|
|
|
|
return isStatusKnown() && Type != file_type::file_not_found;
|
|
|
|
}
|
|
|
|
|
2018-03-28 22:09:09 +00:00
|
|
|
File::~File() = default;
|
2014-02-20 21:59:23 +00:00
|
|
|
|
2018-03-28 22:09:09 +00:00
|
|
|
FileSystem::~FileSystem() = default;
|
2014-02-20 21:59:23 +00:00
|
|
|
|
2014-10-26 22:44:13 +00:00
|
|
|
ErrorOr<std::unique_ptr<MemoryBuffer>>
|
|
|
|
FileSystem::getBufferForFile(const llvm::Twine &Name, int64_t FileSize,
|
|
|
|
bool RequiresNullTerminator, bool IsVolatile) {
|
|
|
|
auto F = openFileForRead(Name);
|
|
|
|
if (!F)
|
|
|
|
return F.getError();
|
|
|
|
|
|
|
|
return (*F)->getBuffer(Name, FileSize, RequiresNullTerminator, IsVolatile);
|
2014-02-20 21:59:23 +00:00
|
|
|
}
|
|
|
|
|
2015-10-05 13:55:20 +00:00
|
|
|
std::error_code FileSystem::makeAbsolute(SmallVectorImpl<char> &Path) const {
|
2016-03-26 18:55:13 +00:00
|
|
|
if (llvm::sys::path::is_absolute(Path))
|
2018-03-28 22:09:09 +00:00
|
|
|
return {};
|
2016-03-26 18:55:13 +00:00
|
|
|
|
2015-10-05 13:55:20 +00:00
|
|
|
auto WorkingDir = getCurrentWorkingDirectory();
|
|
|
|
if (!WorkingDir)
|
|
|
|
return WorkingDir.getError();
|
|
|
|
|
2019-01-16 09:55:32 +00:00
|
|
|
llvm::sys::fs::make_absolute(WorkingDir.get(), Path);
|
|
|
|
return {};
|
2015-10-05 13:55:20 +00:00
|
|
|
}
|
|
|
|
|
2018-05-17 10:26:23 +00:00
|
|
|
std::error_code FileSystem::getRealPath(const Twine &Path,
|
2024-04-12 10:09:04 -07:00
|
|
|
SmallVectorImpl<char> &Output) {
|
2018-05-17 10:26:23 +00:00
|
|
|
return errc::operation_not_permitted;
|
|
|
|
}
|
|
|
|
|
2018-11-08 00:01:32 +00:00
|
|
|
std::error_code FileSystem::isLocal(const Twine &Path, bool &Result) {
|
|
|
|
return errc::operation_not_permitted;
|
|
|
|
}
|
|
|
|
|
2015-10-07 15:48:01 +00:00
|
|
|
bool FileSystem::exists(const Twine &Path) {
|
|
|
|
auto Status = status(Path);
|
|
|
|
return Status && Status->exists();
|
|
|
|
}
|
|
|
|
|
2024-05-07 13:55:44 -07:00
|
|
|
llvm::ErrorOr<bool> FileSystem::equivalent(const Twine &A, const Twine &B) {
|
|
|
|
auto StatusA = status(A);
|
|
|
|
if (!StatusA)
|
|
|
|
return StatusA.getError();
|
|
|
|
auto StatusB = status(B);
|
|
|
|
if (!StatusB)
|
|
|
|
return StatusB.getError();
|
|
|
|
return StatusA->equivalent(*StatusB);
|
|
|
|
}
|
|
|
|
|
2022-03-09 12:23:22 -08:00
|
|
|
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
|
|
|
void FileSystem::dump() const { print(dbgs(), PrintType::RecursiveContents); }
|
|
|
|
#endif
|
|
|
|
|
2016-03-17 02:20:43 +00:00
|
|
|
#ifndef NDEBUG
|
|
|
|
static bool isTraversalComponent(StringRef Component) {
|
2024-05-04 08:46:48 -07:00
|
|
|
return Component == ".." || Component == ".";
|
2016-03-17 02:20:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool pathHasTraversal(StringRef Path) {
|
|
|
|
using namespace llvm::sys;
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2016-03-17 02:20:43 +00:00
|
|
|
for (StringRef Comp : llvm::make_range(path::begin(Path), path::end(Path)))
|
|
|
|
if (isTraversalComponent(Comp))
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-02-20 21:59:23 +00:00
|
|
|
//===-----------------------------------------------------------------------===/
|
|
|
|
// RealFileSystem implementation
|
|
|
|
//===-----------------------------------------------------------------------===/
|
|
|
|
|
2014-03-01 17:21:22 +00:00
|
|
|
namespace {
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// Wrapper around a raw file descriptor.
|
2014-02-20 21:59:23 +00:00
|
|
|
class RealFile : public File {
|
2018-03-28 22:09:09 +00:00
|
|
|
friend class RealFileSystem;
|
|
|
|
|
[Support] Move llvm::MemoryBuffer to sys::fs::file_t
Summary:
On Windows, Posix integer file descriptors are a compatibility layer
over native file handles provided by the C runtime. There is a hard
limit on the maximum number of file descriptors that a process can open,
and the limit is 8192. LLD typically doesn't run into this limit because
it opens input files, maps them into memory, and then immediately closes
the file descriptor. This prevents it from running out of FDs.
For various reasons, I'd like to open handles to every input file and
keep them open during linking. That requires migrating MemoryBuffer over
to taking open native file handles instead of integer FDs.
Reviewers: aganea, Bigcheese
Reviewed By: aganea
Subscribers: smeenai, silvas, mehdi_amini, hiraditya, steven_wu, dexonsmith, dang, llvm-commits, zturner
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63453
llvm-svn: 365588
2019-07-10 00:34:13 +00:00
|
|
|
file_t FD;
|
2014-02-28 21:16:07 +00:00
|
|
|
Status S;
|
2016-06-13 20:40:21 +00:00
|
|
|
std::string RealName;
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2019-10-16 11:16:59 +00:00
|
|
|
RealFile(file_t RawFD, StringRef NewName, StringRef NewRealPathName)
|
|
|
|
: FD(RawFD), S(NewName, {}, {}, {}, {}, {},
|
|
|
|
llvm::sys::fs::file_type::status_error, {}),
|
2016-06-13 20:40:21 +00:00
|
|
|
RealName(NewRealPathName.str()) {
|
[Support] Move llvm::MemoryBuffer to sys::fs::file_t
Summary:
On Windows, Posix integer file descriptors are a compatibility layer
over native file handles provided by the C runtime. There is a hard
limit on the maximum number of file descriptors that a process can open,
and the limit is 8192. LLD typically doesn't run into this limit because
it opens input files, maps them into memory, and then immediately closes
the file descriptor. This prevents it from running out of FDs.
For various reasons, I'd like to open handles to every input file and
keep them open during linking. That requires migrating MemoryBuffer over
to taking open native file handles instead of integer FDs.
Reviewers: aganea, Bigcheese
Reviewed By: aganea
Subscribers: smeenai, silvas, mehdi_amini, hiraditya, steven_wu, dexonsmith, dang, llvm-commits, zturner
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63453
llvm-svn: 365588
2019-07-10 00:34:13 +00:00
|
|
|
assert(FD != kInvalidFile && "Invalid or inactive file descriptor");
|
2014-02-20 21:59:23 +00:00
|
|
|
}
|
2014-02-21 23:39:37 +00:00
|
|
|
|
2014-02-20 21:59:23 +00:00
|
|
|
public:
|
2015-04-11 02:00:23 +00:00
|
|
|
~RealFile() override;
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2014-03-02 09:32:10 +00:00
|
|
|
ErrorOr<Status> status() override;
|
2018-07-24 20:28:07 +00:00
|
|
|
ErrorOr<std::string> getName() override;
|
2015-10-05 21:20:19 +00:00
|
|
|
ErrorOr<std::unique_ptr<MemoryBuffer>> getBuffer(const Twine &Name,
|
|
|
|
int64_t FileSize,
|
|
|
|
bool RequiresNullTerminator,
|
|
|
|
bool IsVolatile) override;
|
2014-06-12 20:37:59 +00:00
|
|
|
std::error_code close() override;
|
2021-11-13 10:13:38 -08:00
|
|
|
void setPath(const Twine &Path) override;
|
2014-02-20 21:59:23 +00:00
|
|
|
};
|
2018-03-28 22:09:09 +00:00
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
2014-02-21 23:39:37 +00:00
|
|
|
RealFile::~RealFile() { close(); }
|
2014-02-20 21:59:23 +00:00
|
|
|
|
|
|
|
ErrorOr<Status> RealFile::status() {
|
[Support] Move llvm::MemoryBuffer to sys::fs::file_t
Summary:
On Windows, Posix integer file descriptors are a compatibility layer
over native file handles provided by the C runtime. There is a hard
limit on the maximum number of file descriptors that a process can open,
and the limit is 8192. LLD typically doesn't run into this limit because
it opens input files, maps them into memory, and then immediately closes
the file descriptor. This prevents it from running out of FDs.
For various reasons, I'd like to open handles to every input file and
keep them open during linking. That requires migrating MemoryBuffer over
to taking open native file handles instead of integer FDs.
Reviewers: aganea, Bigcheese
Reviewed By: aganea
Subscribers: smeenai, silvas, mehdi_amini, hiraditya, steven_wu, dexonsmith, dang, llvm-commits, zturner
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63453
llvm-svn: 365588
2019-07-10 00:34:13 +00:00
|
|
|
assert(FD != kInvalidFile && "cannot stat closed file");
|
2014-02-28 21:16:07 +00:00
|
|
|
if (!S.isStatusKnown()) {
|
|
|
|
file_status RealStatus;
|
2014-06-12 20:37:59 +00:00
|
|
|
if (std::error_code EC = sys::fs::status(FD, RealStatus))
|
2014-02-28 21:16:07 +00:00
|
|
|
return EC;
|
2018-07-24 20:28:07 +00:00
|
|
|
S = Status::copyWithNewName(RealStatus, S.getName());
|
2014-02-28 21:16:07 +00:00
|
|
|
}
|
|
|
|
return S;
|
2014-02-20 21:59:23 +00:00
|
|
|
}
|
|
|
|
|
2018-07-24 20:28:07 +00:00
|
|
|
ErrorOr<std::string> RealFile::getName() {
|
|
|
|
return RealName.empty() ? S.getName().str() : RealName;
|
2016-06-13 20:40:21 +00:00
|
|
|
}
|
|
|
|
|
2014-10-26 22:44:13 +00:00
|
|
|
ErrorOr<std::unique_ptr<MemoryBuffer>>
|
|
|
|
RealFile::getBuffer(const Twine &Name, int64_t FileSize,
|
|
|
|
bool RequiresNullTerminator, bool IsVolatile) {
|
[Support] Move llvm::MemoryBuffer to sys::fs::file_t
Summary:
On Windows, Posix integer file descriptors are a compatibility layer
over native file handles provided by the C runtime. There is a hard
limit on the maximum number of file descriptors that a process can open,
and the limit is 8192. LLD typically doesn't run into this limit because
it opens input files, maps them into memory, and then immediately closes
the file descriptor. This prevents it from running out of FDs.
For various reasons, I'd like to open handles to every input file and
keep them open during linking. That requires migrating MemoryBuffer over
to taking open native file handles instead of integer FDs.
Reviewers: aganea, Bigcheese
Reviewed By: aganea
Subscribers: smeenai, silvas, mehdi_amini, hiraditya, steven_wu, dexonsmith, dang, llvm-commits, zturner
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63453
llvm-svn: 365588
2019-07-10 00:34:13 +00:00
|
|
|
assert(FD != kInvalidFile && "cannot get buffer for closed file");
|
2014-10-26 22:44:13 +00:00
|
|
|
return MemoryBuffer::getOpenFile(FD, Name, FileSize, RequiresNullTerminator,
|
|
|
|
IsVolatile);
|
2014-02-20 21:59:23 +00:00
|
|
|
}
|
|
|
|
|
2014-06-12 20:37:59 +00:00
|
|
|
std::error_code RealFile::close() {
|
[Support] Move llvm::MemoryBuffer to sys::fs::file_t
Summary:
On Windows, Posix integer file descriptors are a compatibility layer
over native file handles provided by the C runtime. There is a hard
limit on the maximum number of file descriptors that a process can open,
and the limit is 8192. LLD typically doesn't run into this limit because
it opens input files, maps them into memory, and then immediately closes
the file descriptor. This prevents it from running out of FDs.
For various reasons, I'd like to open handles to every input file and
keep them open during linking. That requires migrating MemoryBuffer over
to taking open native file handles instead of integer FDs.
Reviewers: aganea, Bigcheese
Reviewed By: aganea
Subscribers: smeenai, silvas, mehdi_amini, hiraditya, steven_wu, dexonsmith, dang, llvm-commits, zturner
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63453
llvm-svn: 365588
2019-07-10 00:34:13 +00:00
|
|
|
std::error_code EC = sys::fs::closeFile(FD);
|
|
|
|
FD = kInvalidFile;
|
2016-03-04 05:26:14 +00:00
|
|
|
return EC;
|
2014-02-20 21:59:23 +00:00
|
|
|
}
|
|
|
|
|
2021-11-13 10:13:38 -08:00
|
|
|
void RealFile::setPath(const Twine &Path) {
|
|
|
|
RealName = Path.str();
|
|
|
|
if (auto Status = status())
|
|
|
|
S = Status.get().copyWithNewName(Status.get(), Path);
|
|
|
|
}
|
|
|
|
|
2014-03-01 17:21:22 +00:00
|
|
|
namespace {
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2019-02-14 12:57:01 +00:00
|
|
|
/// A file system according to your operating system.
|
|
|
|
/// This may be linked to the process's working directory, or maintain its own.
|
|
|
|
///
|
|
|
|
/// Currently, its own working directory is emulated by storing the path and
|
|
|
|
/// sending absolute paths to llvm::sys::fs:: functions.
|
|
|
|
/// A more principled approach would be to push this down a level, modelling
|
|
|
|
/// the working dir as an llvm::sys::fs::WorkingDir or similar.
|
|
|
|
/// This would enable the use of openat()-style functions on some platforms.
|
2014-02-20 21:59:23 +00:00
|
|
|
class RealFileSystem : public FileSystem {
|
|
|
|
public:
|
2019-02-14 12:57:01 +00:00
|
|
|
explicit RealFileSystem(bool LinkCWDToProcess) {
|
|
|
|
if (!LinkCWDToProcess) {
|
|
|
|
SmallString<128> PWD, RealPWD;
|
2023-04-25 11:04:06 -07:00
|
|
|
if (std::error_code EC = llvm::sys::fs::current_path(PWD))
|
|
|
|
WD = EC;
|
|
|
|
else if (llvm::sys::fs::real_path(PWD, RealPWD))
|
|
|
|
WD = WorkingDirectory{PWD, PWD};
|
2019-02-14 12:57:01 +00:00
|
|
|
else
|
2023-04-25 11:04:06 -07:00
|
|
|
WD = WorkingDirectory{PWD, RealPWD};
|
2019-02-14 12:57:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-02 09:32:10 +00:00
|
|
|
ErrorOr<Status> status(const Twine &Path) override;
|
2014-10-26 22:44:13 +00:00
|
|
|
ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override;
|
2014-06-24 19:37:16 +00:00
|
|
|
directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
|
2015-10-05 13:55:20 +00:00
|
|
|
|
|
|
|
llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override;
|
|
|
|
std::error_code setCurrentWorkingDirectory(const Twine &Path) override;
|
2018-11-08 00:01:32 +00:00
|
|
|
std::error_code isLocal(const Twine &Path, bool &Result) override;
|
2018-11-09 15:11:34 +00:00
|
|
|
std::error_code getRealPath(const Twine &Path,
|
2024-04-12 10:09:04 -07:00
|
|
|
SmallVectorImpl<char> &Output) override;
|
2018-10-10 13:27:25 +00:00
|
|
|
|
2022-03-09 12:23:22 -08:00
|
|
|
protected:
|
|
|
|
void printImpl(raw_ostream &OS, PrintType Type,
|
|
|
|
unsigned IndentLevel) const override;
|
|
|
|
|
2018-09-05 09:45:27 +00:00
|
|
|
private:
|
2019-02-14 12:57:01 +00:00
|
|
|
// If this FS has its own working dir, use it to make Path absolute.
|
|
|
|
// The returned twine is safe to use as long as both Storage and Path live.
|
|
|
|
Twine adjustPath(const Twine &Path, SmallVectorImpl<char> &Storage) const {
|
2023-04-25 11:04:06 -07:00
|
|
|
if (!WD || !*WD)
|
2019-02-14 12:57:01 +00:00
|
|
|
return Path;
|
|
|
|
Path.toVector(Storage);
|
2023-04-25 11:04:06 -07:00
|
|
|
sys::fs::make_absolute(WD->get().Resolved, Storage);
|
2019-02-14 12:57:01 +00:00
|
|
|
return Storage;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct WorkingDirectory {
|
|
|
|
// The current working directory, without symlinks resolved. (echo $PWD).
|
|
|
|
SmallString<128> Specified;
|
|
|
|
// The current working directory, with links resolved. (readlink .).
|
|
|
|
SmallString<128> Resolved;
|
|
|
|
};
|
2023-04-25 11:04:06 -07:00
|
|
|
std::optional<llvm::ErrorOr<WorkingDirectory>> WD;
|
2014-02-20 21:59:23 +00:00
|
|
|
};
|
2018-03-28 22:09:09 +00:00
|
|
|
|
|
|
|
} // namespace
|
2014-02-20 21:59:23 +00:00
|
|
|
|
|
|
|
ErrorOr<Status> RealFileSystem::status(const Twine &Path) {
|
2019-02-14 12:57:01 +00:00
|
|
|
SmallString<256> Storage;
|
2014-02-20 21:59:23 +00:00
|
|
|
sys::fs::file_status RealStatus;
|
2019-02-14 12:57:01 +00:00
|
|
|
if (std::error_code EC =
|
|
|
|
sys::fs::status(adjustPath(Path, Storage), RealStatus))
|
2014-02-20 21:59:23 +00:00
|
|
|
return EC;
|
2019-02-23 23:48:47 +00:00
|
|
|
return Status::copyWithNewName(RealStatus, Path);
|
2014-02-20 21:59:23 +00:00
|
|
|
}
|
|
|
|
|
2014-10-26 22:44:13 +00:00
|
|
|
ErrorOr<std::unique_ptr<File>>
|
|
|
|
RealFileSystem::openFileForRead(const Twine &Name) {
|
2019-02-14 12:57:01 +00:00
|
|
|
SmallString<256> RealName, Storage;
|
[Support] Move llvm::MemoryBuffer to sys::fs::file_t
Summary:
On Windows, Posix integer file descriptors are a compatibility layer
over native file handles provided by the C runtime. There is a hard
limit on the maximum number of file descriptors that a process can open,
and the limit is 8192. LLD typically doesn't run into this limit because
it opens input files, maps them into memory, and then immediately closes
the file descriptor. This prevents it from running out of FDs.
For various reasons, I'd like to open handles to every input file and
keep them open during linking. That requires migrating MemoryBuffer over
to taking open native file handles instead of integer FDs.
Reviewers: aganea, Bigcheese
Reviewed By: aganea
Subscribers: smeenai, silvas, mehdi_amini, hiraditya, steven_wu, dexonsmith, dang, llvm-commits, zturner
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D63453
llvm-svn: 365588
2019-07-10 00:34:13 +00:00
|
|
|
Expected<file_t> FDOrErr = sys::fs::openNativeFileForRead(
|
|
|
|
adjustPath(Name, Storage), sys::fs::OF_None, &RealName);
|
|
|
|
if (!FDOrErr)
|
|
|
|
return errorToErrorCode(FDOrErr.takeError());
|
|
|
|
return std::unique_ptr<File>(
|
|
|
|
new RealFile(*FDOrErr, Name.str(), RealName.str()));
|
2014-02-20 21:59:23 +00:00
|
|
|
}
|
|
|
|
|
2015-10-05 13:55:20 +00:00
|
|
|
llvm::ErrorOr<std::string> RealFileSystem::getCurrentWorkingDirectory() const {
|
2023-04-25 11:04:06 -07:00
|
|
|
if (WD && *WD)
|
2024-01-17 20:22:58 -08:00
|
|
|
return std::string(WD->get().Specified);
|
2019-02-14 12:57:01 +00:00
|
|
|
if (WD)
|
2023-04-25 11:04:06 -07:00
|
|
|
return WD->getError();
|
2019-02-14 12:57:01 +00:00
|
|
|
|
|
|
|
SmallString<128> Dir;
|
2015-10-05 13:55:20 +00:00
|
|
|
if (std::error_code EC = llvm::sys::fs::current_path(Dir))
|
|
|
|
return EC;
|
2024-01-17 20:22:58 -08:00
|
|
|
return std::string(Dir);
|
2015-10-05 13:55:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::error_code RealFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
|
2019-02-14 12:57:01 +00:00
|
|
|
if (!WD)
|
|
|
|
return llvm::sys::fs::set_current_path(Path);
|
|
|
|
|
|
|
|
SmallString<128> Absolute, Resolved, Storage;
|
|
|
|
adjustPath(Path, Storage).toVector(Absolute);
|
|
|
|
bool IsDir;
|
|
|
|
if (auto Err = llvm::sys::fs::is_directory(Absolute, IsDir))
|
|
|
|
return Err;
|
|
|
|
if (!IsDir)
|
|
|
|
return std::make_error_code(std::errc::not_a_directory);
|
|
|
|
if (auto Err = llvm::sys::fs::real_path(Absolute, Resolved))
|
|
|
|
return Err;
|
2023-04-25 11:04:06 -07:00
|
|
|
WD = WorkingDirectory{Absolute, Resolved};
|
2018-09-05 09:45:27 +00:00
|
|
|
return std::error_code();
|
2015-10-05 13:55:20 +00:00
|
|
|
}
|
|
|
|
|
2018-11-08 00:01:32 +00:00
|
|
|
std::error_code RealFileSystem::isLocal(const Twine &Path, bool &Result) {
|
2019-02-14 12:57:01 +00:00
|
|
|
SmallString<256> Storage;
|
|
|
|
return llvm::sys::fs::is_local(adjustPath(Path, Storage), Result);
|
2018-11-08 00:01:32 +00:00
|
|
|
}
|
|
|
|
|
2024-04-12 10:09:04 -07:00
|
|
|
std::error_code RealFileSystem::getRealPath(const Twine &Path,
|
|
|
|
SmallVectorImpl<char> &Output) {
|
2019-02-14 12:57:01 +00:00
|
|
|
SmallString<256> Storage;
|
|
|
|
return llvm::sys::fs::real_path(adjustPath(Path, Storage), Output);
|
2018-05-17 10:26:23 +00:00
|
|
|
}
|
|
|
|
|
2022-03-09 12:23:22 -08:00
|
|
|
void RealFileSystem::printImpl(raw_ostream &OS, PrintType Type,
|
|
|
|
unsigned IndentLevel) const {
|
|
|
|
printIndent(OS, IndentLevel);
|
|
|
|
OS << "RealFileSystem using ";
|
|
|
|
if (WD)
|
|
|
|
OS << "own";
|
|
|
|
else
|
|
|
|
OS << "process";
|
|
|
|
OS << " CWD\n";
|
|
|
|
}
|
|
|
|
|
2014-02-20 21:59:23 +00:00
|
|
|
IntrusiveRefCntPtr<FileSystem> vfs::getRealFileSystem() {
|
2019-02-14 12:57:01 +00:00
|
|
|
static IntrusiveRefCntPtr<FileSystem> FS(new RealFileSystem(true));
|
2014-02-20 21:59:23 +00:00
|
|
|
return FS;
|
|
|
|
}
|
|
|
|
|
2019-02-14 12:57:01 +00:00
|
|
|
std::unique_ptr<FileSystem> vfs::createPhysicalFileSystem() {
|
2019-08-15 15:54:37 +00:00
|
|
|
return std::make_unique<RealFileSystem>(false);
|
2019-02-14 12:57:01 +00:00
|
|
|
}
|
|
|
|
|
2014-06-24 19:37:16 +00:00
|
|
|
namespace {
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2018-10-10 13:27:25 +00:00
|
|
|
class RealFSDirIter : public llvm::vfs::detail::DirIterImpl {
|
2014-06-24 19:37:16 +00:00
|
|
|
llvm::sys::fs::directory_iterator Iter;
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2014-06-24 19:37:16 +00:00
|
|
|
public:
|
2017-03-10 21:23:29 +00:00
|
|
|
RealFSDirIter(const Twine &Path, std::error_code &EC) : Iter(Path, EC) {
|
2018-09-14 12:47:38 +00:00
|
|
|
if (Iter != llvm::sys::fs::directory_iterator())
|
|
|
|
CurrentEntry = directory_entry(Iter->path(), Iter->type());
|
2014-06-24 19:37:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::error_code increment() override {
|
|
|
|
std::error_code EC;
|
|
|
|
Iter.increment(EC);
|
2018-09-14 12:47:38 +00:00
|
|
|
CurrentEntry = (Iter == llvm::sys::fs::directory_iterator())
|
|
|
|
? directory_entry()
|
|
|
|
: directory_entry(Iter->path(), Iter->type());
|
2014-06-24 19:37:16 +00:00
|
|
|
return EC;
|
|
|
|
}
|
|
|
|
};
|
2018-03-28 22:09:09 +00:00
|
|
|
|
|
|
|
} // namespace
|
2014-06-24 19:37:16 +00:00
|
|
|
|
|
|
|
directory_iterator RealFileSystem::dir_begin(const Twine &Dir,
|
|
|
|
std::error_code &EC) {
|
2019-02-14 12:57:01 +00:00
|
|
|
SmallString<128> Storage;
|
|
|
|
return directory_iterator(
|
|
|
|
std::make_shared<RealFSDirIter>(adjustPath(Dir, Storage), EC));
|
2014-06-24 19:37:16 +00:00
|
|
|
}
|
|
|
|
|
2014-02-20 21:59:23 +00:00
|
|
|
//===-----------------------------------------------------------------------===/
|
|
|
|
// OverlayFileSystem implementation
|
|
|
|
//===-----------------------------------------------------------------------===/
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2014-02-20 21:59:23 +00:00
|
|
|
OverlayFileSystem::OverlayFileSystem(IntrusiveRefCntPtr<FileSystem> BaseFS) {
|
2016-06-12 20:05:23 +00:00
|
|
|
FSList.push_back(std::move(BaseFS));
|
2014-02-20 21:59:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void OverlayFileSystem::pushOverlay(IntrusiveRefCntPtr<FileSystem> FS) {
|
|
|
|
FSList.push_back(FS);
|
2015-10-05 13:55:20 +00:00
|
|
|
// Synchronize added file systems by duplicating the working directory from
|
|
|
|
// the first one in the list.
|
|
|
|
FS->setCurrentWorkingDirectory(getCurrentWorkingDirectory().get());
|
2014-02-20 21:59:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ErrorOr<Status> OverlayFileSystem::status(const Twine &Path) {
|
|
|
|
// FIXME: handle symlinks that cross file systems
|
|
|
|
for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) {
|
|
|
|
ErrorOr<Status> Status = (*I)->status(Path);
|
2014-06-13 17:20:50 +00:00
|
|
|
if (Status || Status.getError() != llvm::errc::no_such_file_or_directory)
|
2014-02-20 21:59:23 +00:00
|
|
|
return Status;
|
|
|
|
}
|
2014-06-13 17:20:50 +00:00
|
|
|
return make_error_code(llvm::errc::no_such_file_or_directory);
|
2014-02-20 21:59:23 +00:00
|
|
|
}
|
|
|
|
|
2024-04-12 13:34:47 -07:00
|
|
|
bool OverlayFileSystem::exists(const Twine &Path) {
|
|
|
|
// FIXME: handle symlinks that cross file systems
|
|
|
|
for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) {
|
|
|
|
if ((*I)->exists(Path))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-10-26 22:44:13 +00:00
|
|
|
ErrorOr<std::unique_ptr<File>>
|
|
|
|
OverlayFileSystem::openFileForRead(const llvm::Twine &Path) {
|
2014-02-20 21:59:23 +00:00
|
|
|
// FIXME: handle symlinks that cross file systems
|
|
|
|
for (iterator I = overlays_begin(), E = overlays_end(); I != E; ++I) {
|
2014-10-26 22:44:13 +00:00
|
|
|
auto Result = (*I)->openFileForRead(Path);
|
|
|
|
if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
|
|
|
|
return Result;
|
2014-02-20 21:59:23 +00:00
|
|
|
}
|
2014-06-13 17:20:50 +00:00
|
|
|
return make_error_code(llvm::errc::no_such_file_or_directory);
|
2014-02-20 21:59:23 +00:00
|
|
|
}
|
2014-02-21 23:39:37 +00:00
|
|
|
|
2015-10-05 13:55:20 +00:00
|
|
|
llvm::ErrorOr<std::string>
|
|
|
|
OverlayFileSystem::getCurrentWorkingDirectory() const {
|
|
|
|
// All file systems are synchronized, just take the first working directory.
|
|
|
|
return FSList.front()->getCurrentWorkingDirectory();
|
|
|
|
}
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2015-10-05 13:55:20 +00:00
|
|
|
std::error_code
|
|
|
|
OverlayFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
|
|
|
|
for (auto &FS : FSList)
|
|
|
|
if (std::error_code EC = FS->setCurrentWorkingDirectory(Path))
|
|
|
|
return EC;
|
2018-03-28 22:09:09 +00:00
|
|
|
return {};
|
2015-10-05 13:55:20 +00:00
|
|
|
}
|
|
|
|
|
2018-11-08 00:01:32 +00:00
|
|
|
std::error_code OverlayFileSystem::isLocal(const Twine &Path, bool &Result) {
|
|
|
|
for (auto &FS : FSList)
|
|
|
|
if (FS->exists(Path))
|
|
|
|
return FS->isLocal(Path, Result);
|
|
|
|
return errc::no_such_file_or_directory;
|
|
|
|
}
|
|
|
|
|
2024-04-12 10:09:04 -07:00
|
|
|
std::error_code OverlayFileSystem::getRealPath(const Twine &Path,
|
|
|
|
SmallVectorImpl<char> &Output) {
|
2021-09-06 09:10:07 -07:00
|
|
|
for (const auto &FS : FSList)
|
2018-05-18 13:22:49 +00:00
|
|
|
if (FS->exists(Path))
|
2018-11-09 15:11:34 +00:00
|
|
|
return FS->getRealPath(Path, Output);
|
2018-05-18 13:22:49 +00:00
|
|
|
return errc::no_such_file_or_directory;
|
|
|
|
}
|
|
|
|
|
2024-01-30 15:39:18 -08:00
|
|
|
void OverlayFileSystem::visitChildFileSystems(VisitCallbackTy Callback) {
|
|
|
|
for (IntrusiveRefCntPtr<FileSystem> FS : overlays_range()) {
|
|
|
|
Callback(*FS);
|
|
|
|
FS->visitChildFileSystems(Callback);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-09 12:23:22 -08:00
|
|
|
void OverlayFileSystem::printImpl(raw_ostream &OS, PrintType Type,
|
|
|
|
unsigned IndentLevel) const {
|
|
|
|
printIndent(OS, IndentLevel);
|
|
|
|
OS << "OverlayFileSystem\n";
|
|
|
|
if (Type == PrintType::Summary)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (Type == PrintType::Contents)
|
|
|
|
Type = PrintType::Summary;
|
2023-09-27 13:39:30 -07:00
|
|
|
for (const auto &FS : overlays_range())
|
2022-03-09 12:23:22 -08:00
|
|
|
FS->print(OS, Type, IndentLevel + 1);
|
|
|
|
}
|
|
|
|
|
2018-10-10 13:27:25 +00:00
|
|
|
llvm::vfs::detail::DirIterImpl::~DirIterImpl() = default;
|
2014-06-24 19:37:16 +00:00
|
|
|
|
|
|
|
namespace {
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2021-01-16 11:44:14 +10:00
|
|
|
/// Combines and deduplicates directory entries across multiple file systems.
|
|
|
|
class CombiningDirIterImpl : public llvm::vfs::detail::DirIterImpl {
|
|
|
|
using FileSystemPtr = llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>;
|
|
|
|
|
2022-02-03 12:53:22 -08:00
|
|
|
/// Iterators to combine, processed in reverse order.
|
|
|
|
SmallVector<directory_iterator, 8> IterList;
|
|
|
|
/// The iterator currently being traversed.
|
2014-06-24 19:37:16 +00:00
|
|
|
directory_iterator CurrentDirIter;
|
2021-01-16 11:44:14 +10:00
|
|
|
/// The set of names already returned as entries.
|
2014-06-24 19:37:16 +00:00
|
|
|
llvm::StringSet<> SeenNames;
|
|
|
|
|
2022-02-03 12:53:22 -08:00
|
|
|
/// Sets \c CurrentDirIter to the next iterator in the list, or leaves it as
|
|
|
|
/// is (at its end position) if we've already gone through them all.
|
|
|
|
std::error_code incrementIter(bool IsFirstTime) {
|
|
|
|
while (!IterList.empty()) {
|
|
|
|
CurrentDirIter = IterList.back();
|
|
|
|
IterList.pop_back();
|
2014-06-24 19:37:16 +00:00
|
|
|
if (CurrentDirIter != directory_iterator())
|
|
|
|
break; // found
|
|
|
|
}
|
2022-02-03 12:53:22 -08:00
|
|
|
|
|
|
|
if (IsFirstTime && CurrentDirIter == directory_iterator())
|
2022-02-21 21:13:38 -08:00
|
|
|
return errc::no_such_file_or_directory;
|
2018-03-28 22:09:09 +00:00
|
|
|
return {};
|
2014-06-24 19:37:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::error_code incrementDirIter(bool IsFirstTime) {
|
|
|
|
assert((IsFirstTime || CurrentDirIter != directory_iterator()) &&
|
|
|
|
"incrementing past end");
|
|
|
|
std::error_code EC;
|
|
|
|
if (!IsFirstTime)
|
|
|
|
CurrentDirIter.increment(EC);
|
|
|
|
if (!EC && CurrentDirIter == directory_iterator())
|
2022-02-03 12:53:22 -08:00
|
|
|
EC = incrementIter(IsFirstTime);
|
2014-06-24 19:37:16 +00:00
|
|
|
return EC;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::error_code incrementImpl(bool IsFirstTime) {
|
|
|
|
while (true) {
|
|
|
|
std::error_code EC = incrementDirIter(IsFirstTime);
|
|
|
|
if (EC || CurrentDirIter == directory_iterator()) {
|
2018-09-14 12:47:38 +00:00
|
|
|
CurrentEntry = directory_entry();
|
2014-06-24 19:37:16 +00:00
|
|
|
return EC;
|
|
|
|
}
|
|
|
|
CurrentEntry = *CurrentDirIter;
|
2018-09-14 12:47:38 +00:00
|
|
|
StringRef Name = llvm::sys::path::filename(CurrentEntry.path());
|
2014-11-19 02:56:13 +00:00
|
|
|
if (SeenNames.insert(Name).second)
|
2014-06-24 19:37:16 +00:00
|
|
|
return EC; // name not seen before
|
|
|
|
}
|
|
|
|
llvm_unreachable("returned above");
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
2021-01-16 11:44:14 +10:00
|
|
|
CombiningDirIterImpl(ArrayRef<FileSystemPtr> FileSystems, std::string Dir,
|
2022-02-03 12:53:22 -08:00
|
|
|
std::error_code &EC) {
|
2023-09-27 13:39:30 -07:00
|
|
|
for (const auto &FS : FileSystems) {
|
2022-02-03 12:53:22 -08:00
|
|
|
std::error_code FEC;
|
|
|
|
directory_iterator Iter = FS->dir_begin(Dir, FEC);
|
|
|
|
if (FEC && FEC != errc::no_such_file_or_directory) {
|
|
|
|
EC = FEC;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!FEC)
|
|
|
|
IterList.push_back(Iter);
|
2021-01-16 11:44:14 +10:00
|
|
|
}
|
2022-02-03 12:53:22 -08:00
|
|
|
EC = incrementImpl(true);
|
2021-01-16 11:44:14 +10:00
|
|
|
}
|
|
|
|
|
2022-02-03 12:53:22 -08:00
|
|
|
CombiningDirIterImpl(ArrayRef<directory_iterator> DirIters,
|
|
|
|
std::error_code &EC)
|
|
|
|
: IterList(DirIters.begin(), DirIters.end()) {
|
|
|
|
EC = incrementImpl(true);
|
2014-06-24 19:37:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::error_code increment() override { return incrementImpl(false); }
|
|
|
|
};
|
2018-03-28 22:09:09 +00:00
|
|
|
|
|
|
|
} // namespace
|
2014-06-24 19:37:16 +00:00
|
|
|
|
|
|
|
directory_iterator OverlayFileSystem::dir_begin(const Twine &Dir,
|
|
|
|
std::error_code &EC) {
|
2022-02-03 12:53:22 -08:00
|
|
|
directory_iterator Combined = directory_iterator(
|
2021-01-16 11:44:14 +10:00
|
|
|
std::make_shared<CombiningDirIterImpl>(FSList, Dir.str(), EC));
|
2022-02-03 12:53:22 -08:00
|
|
|
if (EC)
|
|
|
|
return {};
|
|
|
|
return Combined;
|
2014-06-24 19:37:16 +00:00
|
|
|
}
|
|
|
|
|
2018-12-29 02:02:13 +00:00
|
|
|
void ProxyFileSystem::anchor() {}
|
|
|
|
|
2018-10-10 13:27:25 +00:00
|
|
|
namespace llvm {
|
2015-10-05 13:55:14 +00:00
|
|
|
namespace vfs {
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2015-10-05 13:55:14 +00:00
|
|
|
namespace detail {
|
|
|
|
|
2022-06-21 10:20:24 +02:00
|
|
|
enum InMemoryNodeKind {
|
|
|
|
IME_File,
|
|
|
|
IME_Directory,
|
|
|
|
IME_HardLink,
|
|
|
|
IME_SymbolicLink,
|
|
|
|
};
|
2015-10-05 13:55:14 +00:00
|
|
|
|
|
|
|
/// The in memory file system is a tree of Nodes. Every node can either be a
|
2022-06-21 10:20:24 +02:00
|
|
|
/// file, symlink, hardlink or a directory.
|
2015-10-05 13:55:14 +00:00
|
|
|
class InMemoryNode {
|
2018-07-11 18:43:07 +00:00
|
|
|
InMemoryNodeKind Kind;
|
2018-09-04 14:15:53 +00:00
|
|
|
std::string FileName;
|
[VirtualFileSystem] InMemoryFileSystem::status: Return a Status with the requested name
Summary:
InMemoryFileSystem::status behaves differently than
RealFileSystem::status. The Name contained in the Status returned by
RealFileSystem::status will be the path as requested by the caller,
whereas InMemoryFileSystem::status returns the normalized path.
For example, when requested the status for "../src/first.h",
RealFileSystem returns a Status with "../src/first.h" as the Name.
InMemoryFileSystem returns "/absolute/path/to/src/first.h".
The reason for this change is that I want to make a unit test in the
clangd testsuite (where we use an InMemoryFileSystem) to reproduce a
bug I get with the clangd program (where a RealFileSystem is used).
This difference in behavior "hides" the bug in the unit test version.
An indirect impact of this change is that a -Wnonportable-include-path
warning is now emitted in test PCH/case-insensitive-include.c. This is
because the real path of the included file (with the wrong case) was not
available previously, whereas it is now.
Reviewers: malaperle, ilya-biryukov, bkramer
Reviewed By: ilya-biryukov
Subscribers: eric_niebler, malaperle, omtcyfz, hokein, bkramer, ilya-biryukov, ioeric, cfe-commits
Differential Revision: https://reviews.llvm.org/D48903
llvm-svn: 339063
2018-08-06 21:48:20 +00:00
|
|
|
|
2015-10-05 13:55:14 +00:00
|
|
|
public:
|
2018-09-04 14:15:53 +00:00
|
|
|
InMemoryNode(llvm::StringRef FileName, InMemoryNodeKind Kind)
|
2020-01-28 20:23:46 +01:00
|
|
|
: Kind(Kind), FileName(std::string(llvm::sys::path::filename(FileName))) {
|
|
|
|
}
|
2018-03-28 22:09:09 +00:00
|
|
|
virtual ~InMemoryNode() = default;
|
|
|
|
|
2022-01-20 15:05:38 +01:00
|
|
|
/// Return the \p Status for this node. \p RequestedName should be the name
|
|
|
|
/// through which the caller referred to this node. It will override
|
|
|
|
/// \p Status::Name in the return value, to mimic the behavior of \p RealFile.
|
|
|
|
virtual Status getStatus(const Twine &RequestedName) const = 0;
|
|
|
|
|
2018-09-04 14:15:53 +00:00
|
|
|
/// Get the filename of this node (the name without the directory part).
|
|
|
|
StringRef getFileName() const { return FileName; }
|
|
|
|
InMemoryNodeKind getKind() const { return Kind; }
|
|
|
|
virtual std::string toString(unsigned Indent) const = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
class InMemoryFile : public InMemoryNode {
|
|
|
|
Status Stat;
|
|
|
|
std::unique_ptr<llvm::MemoryBuffer> Buffer;
|
|
|
|
|
|
|
|
public:
|
|
|
|
InMemoryFile(Status Stat, std::unique_ptr<llvm::MemoryBuffer> Buffer)
|
|
|
|
: InMemoryNode(Stat.getName(), IME_File), Stat(std::move(Stat)),
|
|
|
|
Buffer(std::move(Buffer)) {}
|
|
|
|
|
2022-01-20 15:05:38 +01:00
|
|
|
Status getStatus(const Twine &RequestedName) const override {
|
[VirtualFileSystem] InMemoryFileSystem::status: Return a Status with the requested name
Summary:
InMemoryFileSystem::status behaves differently than
RealFileSystem::status. The Name contained in the Status returned by
RealFileSystem::status will be the path as requested by the caller,
whereas InMemoryFileSystem::status returns the normalized path.
For example, when requested the status for "../src/first.h",
RealFileSystem returns a Status with "../src/first.h" as the Name.
InMemoryFileSystem returns "/absolute/path/to/src/first.h".
The reason for this change is that I want to make a unit test in the
clangd testsuite (where we use an InMemoryFileSystem) to reproduce a
bug I get with the clangd program (where a RealFileSystem is used).
This difference in behavior "hides" the bug in the unit test version.
An indirect impact of this change is that a -Wnonportable-include-path
warning is now emitted in test PCH/case-insensitive-include.c. This is
because the real path of the included file (with the wrong case) was not
available previously, whereas it is now.
Reviewers: malaperle, ilya-biryukov, bkramer
Reviewed By: ilya-biryukov
Subscribers: eric_niebler, malaperle, omtcyfz, hokein, bkramer, ilya-biryukov, ioeric, cfe-commits
Differential Revision: https://reviews.llvm.org/D48903
llvm-svn: 339063
2018-08-06 21:48:20 +00:00
|
|
|
return Status::copyWithNewName(Stat, RequestedName);
|
|
|
|
}
|
2018-09-04 14:15:53 +00:00
|
|
|
llvm::MemoryBuffer *getBuffer() const { return Buffer.get(); }
|
[VirtualFileSystem] InMemoryFileSystem::status: Return a Status with the requested name
Summary:
InMemoryFileSystem::status behaves differently than
RealFileSystem::status. The Name contained in the Status returned by
RealFileSystem::status will be the path as requested by the caller,
whereas InMemoryFileSystem::status returns the normalized path.
For example, when requested the status for "../src/first.h",
RealFileSystem returns a Status with "../src/first.h" as the Name.
InMemoryFileSystem returns "/absolute/path/to/src/first.h".
The reason for this change is that I want to make a unit test in the
clangd testsuite (where we use an InMemoryFileSystem) to reproduce a
bug I get with the clangd program (where a RealFileSystem is used).
This difference in behavior "hides" the bug in the unit test version.
An indirect impact of this change is that a -Wnonportable-include-path
warning is now emitted in test PCH/case-insensitive-include.c. This is
because the real path of the included file (with the wrong case) was not
available previously, whereas it is now.
Reviewers: malaperle, ilya-biryukov, bkramer
Reviewed By: ilya-biryukov
Subscribers: eric_niebler, malaperle, omtcyfz, hokein, bkramer, ilya-biryukov, ioeric, cfe-commits
Differential Revision: https://reviews.llvm.org/D48903
llvm-svn: 339063
2018-08-06 21:48:20 +00:00
|
|
|
|
2018-09-04 14:15:53 +00:00
|
|
|
std::string toString(unsigned Indent) const override {
|
|
|
|
return (std::string(Indent, ' ') + Stat.getName() + "\n").str();
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool classof(const InMemoryNode *N) {
|
|
|
|
return N->getKind() == IME_File;
|
[VirtualFileSystem] InMemoryFileSystem::status: Return a Status with the requested name
Summary:
InMemoryFileSystem::status behaves differently than
RealFileSystem::status. The Name contained in the Status returned by
RealFileSystem::status will be the path as requested by the caller,
whereas InMemoryFileSystem::status returns the normalized path.
For example, when requested the status for "../src/first.h",
RealFileSystem returns a Status with "../src/first.h" as the Name.
InMemoryFileSystem returns "/absolute/path/to/src/first.h".
The reason for this change is that I want to make a unit test in the
clangd testsuite (where we use an InMemoryFileSystem) to reproduce a
bug I get with the clangd program (where a RealFileSystem is used).
This difference in behavior "hides" the bug in the unit test version.
An indirect impact of this change is that a -Wnonportable-include-path
warning is now emitted in test PCH/case-insensitive-include.c. This is
because the real path of the included file (with the wrong case) was not
available previously, whereas it is now.
Reviewers: malaperle, ilya-biryukov, bkramer
Reviewed By: ilya-biryukov
Subscribers: eric_niebler, malaperle, omtcyfz, hokein, bkramer, ilya-biryukov, ioeric, cfe-commits
Differential Revision: https://reviews.llvm.org/D48903
llvm-svn: 339063
2018-08-06 21:48:20 +00:00
|
|
|
}
|
2015-10-05 13:55:14 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
namespace {
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2018-09-04 14:15:53 +00:00
|
|
|
class InMemoryHardLink : public InMemoryNode {
|
|
|
|
const InMemoryFile &ResolvedFile;
|
2015-10-05 13:55:14 +00:00
|
|
|
|
|
|
|
public:
|
2018-09-04 14:15:53 +00:00
|
|
|
InMemoryHardLink(StringRef Path, const InMemoryFile &ResolvedFile)
|
|
|
|
: InMemoryNode(Path, IME_HardLink), ResolvedFile(ResolvedFile) {}
|
|
|
|
const InMemoryFile &getResolvedFile() const { return ResolvedFile; }
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2022-01-20 15:05:38 +01:00
|
|
|
Status getStatus(const Twine &RequestedName) const override {
|
|
|
|
return ResolvedFile.getStatus(RequestedName);
|
|
|
|
}
|
|
|
|
|
2015-10-05 13:55:14 +00:00
|
|
|
std::string toString(unsigned Indent) const override {
|
2018-09-04 14:15:53 +00:00
|
|
|
return std::string(Indent, ' ') + "HardLink to -> " +
|
|
|
|
ResolvedFile.toString(0);
|
2015-10-05 13:55:14 +00:00
|
|
|
}
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2015-10-05 13:55:14 +00:00
|
|
|
static bool classof(const InMemoryNode *N) {
|
2018-09-04 14:15:53 +00:00
|
|
|
return N->getKind() == IME_HardLink;
|
2015-10-05 13:55:14 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-06-21 10:20:24 +02:00
|
|
|
class InMemorySymbolicLink : public InMemoryNode {
|
|
|
|
std::string TargetPath;
|
|
|
|
Status Stat;
|
|
|
|
|
|
|
|
public:
|
|
|
|
InMemorySymbolicLink(StringRef Path, StringRef TargetPath, Status Stat)
|
|
|
|
: InMemoryNode(Path, IME_SymbolicLink), TargetPath(std::move(TargetPath)),
|
|
|
|
Stat(Stat) {}
|
|
|
|
|
|
|
|
std::string toString(unsigned Indent) const override {
|
|
|
|
return std::string(Indent, ' ') + "SymbolicLink to -> " + TargetPath;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status getStatus(const Twine &RequestedName) const override {
|
|
|
|
return Status::copyWithNewName(Stat, RequestedName);
|
|
|
|
}
|
|
|
|
|
|
|
|
StringRef getTargetPath() const { return TargetPath; }
|
|
|
|
|
|
|
|
static bool classof(const InMemoryNode *N) {
|
|
|
|
return N->getKind() == IME_SymbolicLink;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
[VirtualFileSystem] InMemoryFileSystem::status: Return a Status with the requested name
Summary:
InMemoryFileSystem::status behaves differently than
RealFileSystem::status. The Name contained in the Status returned by
RealFileSystem::status will be the path as requested by the caller,
whereas InMemoryFileSystem::status returns the normalized path.
For example, when requested the status for "../src/first.h",
RealFileSystem returns a Status with "../src/first.h" as the Name.
InMemoryFileSystem returns "/absolute/path/to/src/first.h".
The reason for this change is that I want to make a unit test in the
clangd testsuite (where we use an InMemoryFileSystem) to reproduce a
bug I get with the clangd program (where a RealFileSystem is used).
This difference in behavior "hides" the bug in the unit test version.
An indirect impact of this change is that a -Wnonportable-include-path
warning is now emitted in test PCH/case-insensitive-include.c. This is
because the real path of the included file (with the wrong case) was not
available previously, whereas it is now.
Reviewers: malaperle, ilya-biryukov, bkramer
Reviewed By: ilya-biryukov
Subscribers: eric_niebler, malaperle, omtcyfz, hokein, bkramer, ilya-biryukov, ioeric, cfe-commits
Differential Revision: https://reviews.llvm.org/D48903
llvm-svn: 339063
2018-08-06 21:48:20 +00:00
|
|
|
/// Adapt a InMemoryFile for VFS' File interface. The goal is to make
|
|
|
|
/// \p InMemoryFileAdaptor mimic as much as possible the behavior of
|
|
|
|
/// \p RealFile.
|
2015-10-05 13:55:14 +00:00
|
|
|
class InMemoryFileAdaptor : public File {
|
2018-09-04 14:15:53 +00:00
|
|
|
const InMemoryFile &Node;
|
[VirtualFileSystem] InMemoryFileSystem::status: Return a Status with the requested name
Summary:
InMemoryFileSystem::status behaves differently than
RealFileSystem::status. The Name contained in the Status returned by
RealFileSystem::status will be the path as requested by the caller,
whereas InMemoryFileSystem::status returns the normalized path.
For example, when requested the status for "../src/first.h",
RealFileSystem returns a Status with "../src/first.h" as the Name.
InMemoryFileSystem returns "/absolute/path/to/src/first.h".
The reason for this change is that I want to make a unit test in the
clangd testsuite (where we use an InMemoryFileSystem) to reproduce a
bug I get with the clangd program (where a RealFileSystem is used).
This difference in behavior "hides" the bug in the unit test version.
An indirect impact of this change is that a -Wnonportable-include-path
warning is now emitted in test PCH/case-insensitive-include.c. This is
because the real path of the included file (with the wrong case) was not
available previously, whereas it is now.
Reviewers: malaperle, ilya-biryukov, bkramer
Reviewed By: ilya-biryukov
Subscribers: eric_niebler, malaperle, omtcyfz, hokein, bkramer, ilya-biryukov, ioeric, cfe-commits
Differential Revision: https://reviews.llvm.org/D48903
llvm-svn: 339063
2018-08-06 21:48:20 +00:00
|
|
|
/// The name to use when returning a Status for this file.
|
|
|
|
std::string RequestedName;
|
2015-10-05 13:55:14 +00:00
|
|
|
|
|
|
|
public:
|
2018-09-04 14:15:53 +00:00
|
|
|
explicit InMemoryFileAdaptor(const InMemoryFile &Node,
|
|
|
|
std::string RequestedName)
|
[VirtualFileSystem] InMemoryFileSystem::status: Return a Status with the requested name
Summary:
InMemoryFileSystem::status behaves differently than
RealFileSystem::status. The Name contained in the Status returned by
RealFileSystem::status will be the path as requested by the caller,
whereas InMemoryFileSystem::status returns the normalized path.
For example, when requested the status for "../src/first.h",
RealFileSystem returns a Status with "../src/first.h" as the Name.
InMemoryFileSystem returns "/absolute/path/to/src/first.h".
The reason for this change is that I want to make a unit test in the
clangd testsuite (where we use an InMemoryFileSystem) to reproduce a
bug I get with the clangd program (where a RealFileSystem is used).
This difference in behavior "hides" the bug in the unit test version.
An indirect impact of this change is that a -Wnonportable-include-path
warning is now emitted in test PCH/case-insensitive-include.c. This is
because the real path of the included file (with the wrong case) was not
available previously, whereas it is now.
Reviewers: malaperle, ilya-biryukov, bkramer
Reviewed By: ilya-biryukov
Subscribers: eric_niebler, malaperle, omtcyfz, hokein, bkramer, ilya-biryukov, ioeric, cfe-commits
Differential Revision: https://reviews.llvm.org/D48903
llvm-svn: 339063
2018-08-06 21:48:20 +00:00
|
|
|
: Node(Node), RequestedName(std::move(RequestedName)) {}
|
2015-10-05 13:55:14 +00:00
|
|
|
|
[VirtualFileSystem] InMemoryFileSystem::status: Return a Status with the requested name
Summary:
InMemoryFileSystem::status behaves differently than
RealFileSystem::status. The Name contained in the Status returned by
RealFileSystem::status will be the path as requested by the caller,
whereas InMemoryFileSystem::status returns the normalized path.
For example, when requested the status for "../src/first.h",
RealFileSystem returns a Status with "../src/first.h" as the Name.
InMemoryFileSystem returns "/absolute/path/to/src/first.h".
The reason for this change is that I want to make a unit test in the
clangd testsuite (where we use an InMemoryFileSystem) to reproduce a
bug I get with the clangd program (where a RealFileSystem is used).
This difference in behavior "hides" the bug in the unit test version.
An indirect impact of this change is that a -Wnonportable-include-path
warning is now emitted in test PCH/case-insensitive-include.c. This is
because the real path of the included file (with the wrong case) was not
available previously, whereas it is now.
Reviewers: malaperle, ilya-biryukov, bkramer
Reviewed By: ilya-biryukov
Subscribers: eric_niebler, malaperle, omtcyfz, hokein, bkramer, ilya-biryukov, ioeric, cfe-commits
Differential Revision: https://reviews.llvm.org/D48903
llvm-svn: 339063
2018-08-06 21:48:20 +00:00
|
|
|
llvm::ErrorOr<Status> status() override {
|
|
|
|
return Node.getStatus(RequestedName);
|
|
|
|
}
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2015-10-05 13:55:14 +00:00
|
|
|
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
|
2015-10-05 21:20:19 +00:00
|
|
|
getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
|
|
|
|
bool IsVolatile) override {
|
2015-10-05 13:55:14 +00:00
|
|
|
llvm::MemoryBuffer *Buf = Node.getBuffer();
|
|
|
|
return llvm::MemoryBuffer::getMemBuffer(
|
|
|
|
Buf->getBuffer(), Buf->getBufferIdentifier(), RequiresNullTerminator);
|
|
|
|
}
|
2018-03-28 22:09:09 +00:00
|
|
|
|
|
|
|
std::error_code close() override { return {}; }
|
2021-11-13 10:13:38 -08:00
|
|
|
|
|
|
|
void setPath(const Twine &Path) override { RequestedName = Path.str(); }
|
2015-10-05 13:55:14 +00:00
|
|
|
};
|
2018-03-28 22:09:09 +00:00
|
|
|
} // namespace
|
2015-10-05 13:55:14 +00:00
|
|
|
|
|
|
|
class InMemoryDirectory : public InMemoryNode {
|
2018-09-04 14:15:53 +00:00
|
|
|
Status Stat;
|
2023-07-19 22:25:40 -07:00
|
|
|
std::map<std::string, std::unique_ptr<InMemoryNode>> Entries;
|
2015-10-05 13:55:14 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
InMemoryDirectory(Status Stat)
|
2018-09-04 14:15:53 +00:00
|
|
|
: InMemoryNode(Stat.getName(), IME_Directory), Stat(std::move(Stat)) {}
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2018-09-04 14:15:53 +00:00
|
|
|
/// Return the \p Status for this node. \p RequestedName should be the name
|
|
|
|
/// through which the caller referred to this node. It will override
|
|
|
|
/// \p Status::Name in the return value, to mimic the behavior of \p RealFile.
|
2022-01-20 15:05:38 +01:00
|
|
|
Status getStatus(const Twine &RequestedName) const override {
|
2018-09-04 14:15:53 +00:00
|
|
|
return Status::copyWithNewName(Stat, RequestedName);
|
|
|
|
}
|
2021-09-29 15:25:15 +02:00
|
|
|
|
|
|
|
UniqueID getUniqueID() const { return Stat.getUniqueID(); }
|
|
|
|
|
2022-06-21 16:16:32 +02:00
|
|
|
InMemoryNode *getChild(StringRef Name) const {
|
2023-07-19 22:25:40 -07:00
|
|
|
auto I = Entries.find(Name.str());
|
2015-10-05 13:55:14 +00:00
|
|
|
if (I != Entries.end())
|
|
|
|
return I->second.get();
|
|
|
|
return nullptr;
|
|
|
|
}
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2015-10-05 13:55:14 +00:00
|
|
|
InMemoryNode *addChild(StringRef Name, std::unique_ptr<InMemoryNode> Child) {
|
2023-07-22 00:00:57 -07:00
|
|
|
return Entries.emplace(Name, std::move(Child)).first->second.get();
|
2015-10-05 13:55:14 +00:00
|
|
|
}
|
|
|
|
|
2018-03-28 22:09:09 +00:00
|
|
|
using const_iterator = decltype(Entries)::const_iterator;
|
|
|
|
|
2015-10-05 13:55:14 +00:00
|
|
|
const_iterator begin() const { return Entries.begin(); }
|
|
|
|
const_iterator end() const { return Entries.end(); }
|
|
|
|
|
|
|
|
std::string toString(unsigned Indent) const override {
|
|
|
|
std::string Result =
|
2018-09-04 14:15:53 +00:00
|
|
|
(std::string(Indent, ' ') + Stat.getName() + "\n").str();
|
2018-03-28 22:09:09 +00:00
|
|
|
for (const auto &Entry : Entries)
|
2015-10-05 13:55:14 +00:00
|
|
|
Result += Entry.second->toString(Indent + 2);
|
|
|
|
return Result;
|
|
|
|
}
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2015-10-05 13:55:14 +00:00
|
|
|
static bool classof(const InMemoryNode *N) {
|
|
|
|
return N->getKind() == IME_Directory;
|
|
|
|
}
|
|
|
|
};
|
2018-03-28 22:09:09 +00:00
|
|
|
|
|
|
|
} // namespace detail
|
2015-10-05 13:55:14 +00:00
|
|
|
|
2021-09-29 15:25:15 +02:00
|
|
|
// The UniqueID of in-memory files is derived from path and content.
|
|
|
|
// This avoids difficulties in creating exactly equivalent in-memory FSes,
|
|
|
|
// as often needed in multithreaded programs.
|
|
|
|
static sys::fs::UniqueID getUniqueID(hash_code Hash) {
|
|
|
|
return sys::fs::UniqueID(std::numeric_limits<uint64_t>::max(),
|
|
|
|
uint64_t(size_t(Hash)));
|
|
|
|
}
|
|
|
|
static sys::fs::UniqueID getFileID(sys::fs::UniqueID Parent,
|
|
|
|
llvm::StringRef Name,
|
|
|
|
llvm::StringRef Contents) {
|
|
|
|
return getUniqueID(llvm::hash_combine(Parent.getFile(), Name, Contents));
|
|
|
|
}
|
|
|
|
static sys::fs::UniqueID getDirectoryID(sys::fs::UniqueID Parent,
|
|
|
|
llvm::StringRef Name) {
|
|
|
|
return getUniqueID(llvm::hash_combine(Parent.getFile(), Name));
|
|
|
|
}
|
|
|
|
|
2022-01-20 15:07:39 +01:00
|
|
|
Status detail::NewInMemoryNodeInfo::makeStatus() const {
|
|
|
|
UniqueID UID =
|
|
|
|
(Type == sys::fs::file_type::directory_file)
|
|
|
|
? getDirectoryID(DirUID, Name)
|
|
|
|
: getFileID(DirUID, Name, Buffer ? Buffer->getBuffer() : "");
|
|
|
|
|
|
|
|
return Status(Path, UID, llvm::sys::toTimePoint(ModificationTime), User,
|
|
|
|
Group, Buffer ? Buffer->getBufferSize() : 0, Type, Perms);
|
|
|
|
}
|
|
|
|
|
2015-10-12 16:16:39 +00:00
|
|
|
InMemoryFileSystem::InMemoryFileSystem(bool UseNormalizedPaths)
|
2015-10-05 13:55:14 +00:00
|
|
|
: Root(new detail::InMemoryDirectory(
|
2021-09-29 15:25:15 +02:00
|
|
|
Status("", getDirectoryID(llvm::sys::fs::UniqueID(), ""),
|
|
|
|
llvm::sys::TimePoint<>(), 0, 0, 0,
|
|
|
|
llvm::sys::fs::file_type::directory_file,
|
2015-10-12 16:16:39 +00:00
|
|
|
llvm::sys::fs::perms::all_all))),
|
|
|
|
UseNormalizedPaths(UseNormalizedPaths) {}
|
2015-10-05 13:55:14 +00:00
|
|
|
|
2018-03-28 22:09:09 +00:00
|
|
|
InMemoryFileSystem::~InMemoryFileSystem() = default;
|
2015-10-05 13:55:14 +00:00
|
|
|
|
2015-10-09 13:03:22 +00:00
|
|
|
std::string InMemoryFileSystem::toString() const {
|
2015-10-05 13:55:14 +00:00
|
|
|
return Root->toString(/*Indent=*/0);
|
|
|
|
}
|
|
|
|
|
2015-10-12 16:16:39 +00:00
|
|
|
bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime,
|
2017-11-09 16:01:16 +00:00
|
|
|
std::unique_ptr<llvm::MemoryBuffer> Buffer,
|
2022-12-16 08:49:10 +00:00
|
|
|
std::optional<uint32_t> User,
|
|
|
|
std::optional<uint32_t> Group,
|
|
|
|
std::optional<llvm::sys::fs::file_type> Type,
|
|
|
|
std::optional<llvm::sys::fs::perms> Perms,
|
2022-01-20 15:07:39 +01:00
|
|
|
MakeNodeFn MakeNode) {
|
2015-10-05 13:55:14 +00:00
|
|
|
SmallString<128> Path;
|
|
|
|
P.toVector(Path);
|
|
|
|
|
|
|
|
// Fix up relative paths. This just prepends the current working directory.
|
2015-10-05 13:55:20 +00:00
|
|
|
std::error_code EC = makeAbsolute(Path);
|
2015-10-05 13:55:14 +00:00
|
|
|
assert(!EC);
|
|
|
|
(void)EC;
|
|
|
|
|
2015-10-12 16:16:39 +00:00
|
|
|
if (useNormalizedPaths())
|
2015-11-09 19:12:18 +00:00
|
|
|
llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
|
2015-10-12 13:30:38 +00:00
|
|
|
|
2015-10-12 16:16:39 +00:00
|
|
|
if (Path.empty())
|
|
|
|
return false;
|
2015-10-12 13:30:38 +00:00
|
|
|
|
2015-10-12 16:16:39 +00:00
|
|
|
detail::InMemoryDirectory *Dir = Root.get();
|
2017-11-09 16:01:16 +00:00
|
|
|
auto I = llvm::sys::path::begin(Path), E = sys::path::end(Path);
|
2022-06-18 23:07:11 -07:00
|
|
|
const auto ResolvedUser = User.value_or(0);
|
|
|
|
const auto ResolvedGroup = Group.value_or(0);
|
|
|
|
const auto ResolvedType = Type.value_or(sys::fs::file_type::regular_file);
|
|
|
|
const auto ResolvedPerms = Perms.value_or(sys::fs::all_all);
|
2017-11-09 16:01:16 +00:00
|
|
|
// Any intermediate directories we create should be accessible by
|
|
|
|
// the owner, even if Perms says otherwise for the final path.
|
|
|
|
const auto NewDirectoryPerms = ResolvedPerms | sys::fs::owner_all;
|
2024-06-06 17:32:50 +02:00
|
|
|
|
|
|
|
StringRef Name = *I;
|
2015-10-05 13:55:14 +00:00
|
|
|
while (true) {
|
2024-06-06 17:32:50 +02:00
|
|
|
Name = *I;
|
2015-10-05 13:55:14 +00:00
|
|
|
++I;
|
2024-06-06 17:32:50 +02:00
|
|
|
if (I == E)
|
|
|
|
break;
|
|
|
|
detail::InMemoryNode *Node = Dir->getChild(Name);
|
2015-10-05 13:55:14 +00:00
|
|
|
if (!Node) {
|
2024-06-06 17:32:50 +02:00
|
|
|
// This isn't the last element, so we create a new directory.
|
2015-10-05 13:55:14 +00:00
|
|
|
Status Stat(
|
|
|
|
StringRef(Path.str().begin(), Name.end() - Path.str().begin()),
|
2021-09-29 15:25:15 +02:00
|
|
|
getDirectoryID(Dir->getUniqueID(), Name),
|
|
|
|
llvm::sys::toTimePoint(ModificationTime), ResolvedUser, ResolvedGroup,
|
|
|
|
0, sys::fs::file_type::directory_file, NewDirectoryPerms);
|
2015-10-05 13:55:14 +00:00
|
|
|
Dir = cast<detail::InMemoryDirectory>(Dir->addChild(
|
2019-08-15 15:54:37 +00:00
|
|
|
Name, std::make_unique<detail::InMemoryDirectory>(std::move(Stat))));
|
2015-10-05 13:55:14 +00:00
|
|
|
continue;
|
|
|
|
}
|
2024-06-06 17:32:50 +02:00
|
|
|
// Creating file under another file.
|
|
|
|
if (!isa<detail::InMemoryDirectory>(Node))
|
|
|
|
return false;
|
|
|
|
Dir = cast<detail::InMemoryDirectory>(Node);
|
|
|
|
}
|
|
|
|
detail::InMemoryNode *Node = Dir->getChild(Name);
|
|
|
|
if (!Node) {
|
|
|
|
Dir->addChild(Name,
|
|
|
|
MakeNode({Dir->getUniqueID(), Path, Name, ModificationTime,
|
|
|
|
std::move(Buffer), ResolvedUser, ResolvedGroup,
|
|
|
|
ResolvedType, ResolvedPerms}));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (isa<detail::InMemoryDirectory>(Node))
|
|
|
|
return ResolvedType == sys::fs::file_type::directory_file;
|
2015-10-05 13:55:14 +00:00
|
|
|
|
2024-06-06 17:32:50 +02:00
|
|
|
assert((isa<detail::InMemoryFile>(Node) ||
|
|
|
|
isa<detail::InMemoryHardLink>(Node)) &&
|
|
|
|
"Must be either file, hardlink or directory!");
|
|
|
|
|
|
|
|
// Return false only if the new file is different from the existing one.
|
|
|
|
if (auto *Link = dyn_cast<detail::InMemoryHardLink>(Node)) {
|
|
|
|
return Link->getResolvedFile().getBuffer()->getBuffer() ==
|
|
|
|
Buffer->getBuffer();
|
2015-10-05 13:55:14 +00:00
|
|
|
}
|
2024-06-06 17:32:50 +02:00
|
|
|
return cast<detail::InMemoryFile>(Node)->getBuffer()->getBuffer() ==
|
|
|
|
Buffer->getBuffer();
|
2015-10-05 13:55:14 +00:00
|
|
|
}
|
|
|
|
|
2018-09-04 14:15:53 +00:00
|
|
|
bool InMemoryFileSystem::addFile(const Twine &P, time_t ModificationTime,
|
|
|
|
std::unique_ptr<llvm::MemoryBuffer> Buffer,
|
2022-12-16 08:49:10 +00:00
|
|
|
std::optional<uint32_t> User,
|
|
|
|
std::optional<uint32_t> Group,
|
|
|
|
std::optional<llvm::sys::fs::file_type> Type,
|
|
|
|
std::optional<llvm::sys::fs::perms> Perms) {
|
2018-09-04 14:15:53 +00:00
|
|
|
return addFile(P, ModificationTime, std::move(Buffer), User, Group, Type,
|
2022-01-20 15:07:39 +01:00
|
|
|
Perms,
|
|
|
|
[](detail::NewInMemoryNodeInfo NNI)
|
|
|
|
-> std::unique_ptr<detail::InMemoryNode> {
|
|
|
|
Status Stat = NNI.makeStatus();
|
|
|
|
if (Stat.getType() == sys::fs::file_type::directory_file)
|
|
|
|
return std::make_unique<detail::InMemoryDirectory>(Stat);
|
|
|
|
return std::make_unique<detail::InMemoryFile>(
|
|
|
|
Stat, std::move(NNI.Buffer));
|
|
|
|
});
|
2018-09-04 14:15:53 +00:00
|
|
|
}
|
|
|
|
|
2022-12-16 08:49:10 +00:00
|
|
|
bool InMemoryFileSystem::addFileNoOwn(
|
|
|
|
const Twine &P, time_t ModificationTime,
|
|
|
|
const llvm::MemoryBufferRef &Buffer, std::optional<uint32_t> User,
|
|
|
|
std::optional<uint32_t> Group, std::optional<llvm::sys::fs::file_type> Type,
|
|
|
|
std::optional<llvm::sys::fs::perms> Perms) {
|
2020-11-05 18:23:19 -05:00
|
|
|
return addFile(P, ModificationTime, llvm::MemoryBuffer::getMemBuffer(Buffer),
|
2017-11-09 16:01:16 +00:00
|
|
|
std::move(User), std::move(Group), std::move(Type),
|
2022-01-20 15:07:39 +01:00
|
|
|
std::move(Perms),
|
|
|
|
[](detail::NewInMemoryNodeInfo NNI)
|
|
|
|
-> std::unique_ptr<detail::InMemoryNode> {
|
|
|
|
Status Stat = NNI.makeStatus();
|
|
|
|
if (Stat.getType() == sys::fs::file_type::directory_file)
|
|
|
|
return std::make_unique<detail::InMemoryDirectory>(Stat);
|
|
|
|
return std::make_unique<detail::InMemoryFile>(
|
|
|
|
Stat, std::move(NNI.Buffer));
|
|
|
|
});
|
2015-10-06 10:04:08 +00:00
|
|
|
}
|
|
|
|
|
2022-06-21 10:20:24 +02:00
|
|
|
detail::NamedNodeOrError
|
|
|
|
InMemoryFileSystem::lookupNode(const Twine &P, bool FollowFinalSymlink,
|
|
|
|
size_t SymlinkDepth) const {
|
2015-10-05 13:55:14 +00:00
|
|
|
SmallString<128> Path;
|
|
|
|
P.toVector(Path);
|
|
|
|
|
|
|
|
// Fix up relative paths. This just prepends the current working directory.
|
2022-06-21 16:16:32 +02:00
|
|
|
std::error_code EC = makeAbsolute(Path);
|
2015-10-05 13:55:14 +00:00
|
|
|
assert(!EC);
|
|
|
|
(void)EC;
|
|
|
|
|
2022-06-21 16:16:32 +02:00
|
|
|
if (useNormalizedPaths())
|
2015-11-09 19:12:18 +00:00
|
|
|
llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
|
2015-10-12 13:30:38 +00:00
|
|
|
|
2022-06-21 16:16:32 +02:00
|
|
|
const detail::InMemoryDirectory *Dir = Root.get();
|
2015-10-12 16:16:39 +00:00
|
|
|
if (Path.empty())
|
2022-06-21 10:20:24 +02:00
|
|
|
return detail::NamedNodeOrError(Path, Dir);
|
2015-10-09 13:03:22 +00:00
|
|
|
|
2015-10-12 16:16:39 +00:00
|
|
|
auto I = llvm::sys::path::begin(Path), E = llvm::sys::path::end(Path);
|
2015-10-05 13:55:14 +00:00
|
|
|
while (true) {
|
|
|
|
detail::InMemoryNode *Node = Dir->getChild(*I);
|
|
|
|
++I;
|
|
|
|
if (!Node)
|
|
|
|
return errc::no_such_file_or_directory;
|
|
|
|
|
2022-06-21 10:20:24 +02:00
|
|
|
if (auto Symlink = dyn_cast<detail::InMemorySymbolicLink>(Node)) {
|
|
|
|
// If we're at the end of the path, and we're not following through
|
|
|
|
// terminal symlinks, then we're done.
|
|
|
|
if (I == E && !FollowFinalSymlink)
|
|
|
|
return detail::NamedNodeOrError(Path, Symlink);
|
|
|
|
|
|
|
|
if (SymlinkDepth > InMemoryFileSystem::MaxSymlinkDepth)
|
|
|
|
return errc::no_such_file_or_directory;
|
|
|
|
|
|
|
|
SmallString<128> TargetPath = Symlink->getTargetPath();
|
|
|
|
if (std::error_code EC = makeAbsolute(TargetPath))
|
|
|
|
return EC;
|
|
|
|
|
|
|
|
// Keep going with the target. We always want to follow symlinks here
|
|
|
|
// because we're either at the end of a path that we want to follow, or
|
|
|
|
// not at the end of a path, in which case we need to follow the symlink
|
|
|
|
// regardless.
|
|
|
|
auto Target =
|
|
|
|
lookupNode(TargetPath, /*FollowFinalSymlink=*/true, SymlinkDepth + 1);
|
|
|
|
if (!Target || I == E)
|
|
|
|
return Target;
|
|
|
|
|
|
|
|
if (!isa<detail::InMemoryDirectory>(*Target))
|
|
|
|
return errc::no_such_file_or_directory;
|
|
|
|
|
|
|
|
// Otherwise, continue on the search in the symlinked directory.
|
|
|
|
Dir = cast<detail::InMemoryDirectory>(*Target);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2015-10-05 13:55:14 +00:00
|
|
|
// Return the file if it's at the end of the path.
|
|
|
|
if (auto File = dyn_cast<detail::InMemoryFile>(Node)) {
|
|
|
|
if (I == E)
|
2022-06-21 10:20:24 +02:00
|
|
|
return detail::NamedNodeOrError(Path, File);
|
2015-10-05 13:55:14 +00:00
|
|
|
return errc::no_such_file_or_directory;
|
|
|
|
}
|
|
|
|
|
2018-09-04 14:15:53 +00:00
|
|
|
// If Node is HardLink then return the resolved file.
|
|
|
|
if (auto File = dyn_cast<detail::InMemoryHardLink>(Node)) {
|
|
|
|
if (I == E)
|
2022-06-21 10:20:24 +02:00
|
|
|
return detail::NamedNodeOrError(Path, &File->getResolvedFile());
|
2018-09-04 14:15:53 +00:00
|
|
|
return errc::no_such_file_or_directory;
|
|
|
|
}
|
2015-10-05 13:55:14 +00:00
|
|
|
// Traverse directories.
|
|
|
|
Dir = cast<detail::InMemoryDirectory>(Node);
|
|
|
|
if (I == E)
|
2022-06-21 10:20:24 +02:00
|
|
|
return detail::NamedNodeOrError(Path, Dir);
|
2015-10-05 13:55:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-21 16:12:09 +02:00
|
|
|
bool InMemoryFileSystem::addHardLink(const Twine &NewLink,
|
|
|
|
const Twine &Target) {
|
2022-06-21 10:20:24 +02:00
|
|
|
auto NewLinkNode = lookupNode(NewLink, /*FollowFinalSymlink=*/false);
|
|
|
|
// Whether symlinks in the hardlink target are followed is
|
|
|
|
// implementation-defined in POSIX.
|
|
|
|
// We're following symlinks here to be consistent with macOS.
|
|
|
|
auto TargetNode = lookupNode(Target, /*FollowFinalSymlink=*/true);
|
2018-09-04 14:15:53 +00:00
|
|
|
// FromPath must not have been added before. ToPath must have been added
|
|
|
|
// before. Resolved ToPath must be a File.
|
2022-06-21 16:12:09 +02:00
|
|
|
if (!TargetNode || NewLinkNode || !isa<detail::InMemoryFile>(*TargetNode))
|
2018-09-04 14:15:53 +00:00
|
|
|
return false;
|
2022-12-02 21:11:44 -08:00
|
|
|
return addFile(NewLink, 0, nullptr, std::nullopt, std::nullopt, std::nullopt,
|
|
|
|
std::nullopt, [&](detail::NewInMemoryNodeInfo NNI) {
|
2022-01-20 15:07:39 +01:00
|
|
|
return std::make_unique<detail::InMemoryHardLink>(
|
2022-06-21 16:12:09 +02:00
|
|
|
NNI.Path.str(),
|
|
|
|
*cast<detail::InMemoryFile>(*TargetNode));
|
2022-01-20 15:07:39 +01:00
|
|
|
});
|
2018-09-04 14:15:53 +00:00
|
|
|
}
|
|
|
|
|
2022-12-16 08:49:10 +00:00
|
|
|
bool InMemoryFileSystem::addSymbolicLink(
|
|
|
|
const Twine &NewLink, const Twine &Target, time_t ModificationTime,
|
|
|
|
std::optional<uint32_t> User, std::optional<uint32_t> Group,
|
|
|
|
std::optional<llvm::sys::fs::perms> Perms) {
|
2022-06-21 10:20:24 +02:00
|
|
|
auto NewLinkNode = lookupNode(NewLink, /*FollowFinalSymlink=*/false);
|
|
|
|
if (NewLinkNode)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
SmallString<128> NewLinkStr, TargetStr;
|
|
|
|
NewLink.toVector(NewLinkStr);
|
|
|
|
Target.toVector(TargetStr);
|
|
|
|
|
|
|
|
return addFile(NewLinkStr, ModificationTime, nullptr, User, Group,
|
|
|
|
sys::fs::file_type::symlink_file, Perms,
|
|
|
|
[&](detail::NewInMemoryNodeInfo NNI) {
|
|
|
|
return std::make_unique<detail::InMemorySymbolicLink>(
|
|
|
|
NewLinkStr, TargetStr, NNI.makeStatus());
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2015-10-05 13:55:14 +00:00
|
|
|
llvm::ErrorOr<Status> InMemoryFileSystem::status(const Twine &Path) {
|
2022-06-21 10:20:24 +02:00
|
|
|
auto Node = lookupNode(Path, /*FollowFinalSymlink=*/true);
|
2015-10-05 13:55:14 +00:00
|
|
|
if (Node)
|
2022-01-20 15:05:38 +01:00
|
|
|
return (*Node)->getStatus(Path);
|
2015-10-05 13:55:14 +00:00
|
|
|
return Node.getError();
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::ErrorOr<std::unique_ptr<File>>
|
|
|
|
InMemoryFileSystem::openFileForRead(const Twine &Path) {
|
2022-06-21 10:20:24 +02:00
|
|
|
auto Node = lookupNode(Path,/*FollowFinalSymlink=*/true);
|
2015-10-05 13:55:14 +00:00
|
|
|
if (!Node)
|
|
|
|
return Node.getError();
|
|
|
|
|
|
|
|
// When we have a file provide a heap-allocated wrapper for the memory buffer
|
|
|
|
// to match the ownership semantics for File.
|
|
|
|
if (auto *F = dyn_cast<detail::InMemoryFile>(*Node))
|
[VirtualFileSystem] InMemoryFileSystem::status: Return a Status with the requested name
Summary:
InMemoryFileSystem::status behaves differently than
RealFileSystem::status. The Name contained in the Status returned by
RealFileSystem::status will be the path as requested by the caller,
whereas InMemoryFileSystem::status returns the normalized path.
For example, when requested the status for "../src/first.h",
RealFileSystem returns a Status with "../src/first.h" as the Name.
InMemoryFileSystem returns "/absolute/path/to/src/first.h".
The reason for this change is that I want to make a unit test in the
clangd testsuite (where we use an InMemoryFileSystem) to reproduce a
bug I get with the clangd program (where a RealFileSystem is used).
This difference in behavior "hides" the bug in the unit test version.
An indirect impact of this change is that a -Wnonportable-include-path
warning is now emitted in test PCH/case-insensitive-include.c. This is
because the real path of the included file (with the wrong case) was not
available previously, whereas it is now.
Reviewers: malaperle, ilya-biryukov, bkramer
Reviewed By: ilya-biryukov
Subscribers: eric_niebler, malaperle, omtcyfz, hokein, bkramer, ilya-biryukov, ioeric, cfe-commits
Differential Revision: https://reviews.llvm.org/D48903
llvm-svn: 339063
2018-08-06 21:48:20 +00:00
|
|
|
return std::unique_ptr<File>(
|
|
|
|
new detail::InMemoryFileAdaptor(*F, Path.str()));
|
2015-10-05 13:55:14 +00:00
|
|
|
|
|
|
|
// FIXME: errc::not_a_file?
|
|
|
|
return make_error_code(llvm::errc::invalid_argument);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Adaptor from InMemoryDir::iterator to directory_iterator.
|
2022-06-21 16:20:53 +02:00
|
|
|
class InMemoryFileSystem::DirIterator : public llvm::vfs::detail::DirIterImpl {
|
2022-06-21 10:20:24 +02:00
|
|
|
const InMemoryFileSystem *FS;
|
2015-10-05 13:55:14 +00:00
|
|
|
detail::InMemoryDirectory::const_iterator I;
|
|
|
|
detail::InMemoryDirectory::const_iterator E;
|
[VirtualFileSystem] InMemoryFileSystem::status: Return a Status with the requested name
Summary:
InMemoryFileSystem::status behaves differently than
RealFileSystem::status. The Name contained in the Status returned by
RealFileSystem::status will be the path as requested by the caller,
whereas InMemoryFileSystem::status returns the normalized path.
For example, when requested the status for "../src/first.h",
RealFileSystem returns a Status with "../src/first.h" as the Name.
InMemoryFileSystem returns "/absolute/path/to/src/first.h".
The reason for this change is that I want to make a unit test in the
clangd testsuite (where we use an InMemoryFileSystem) to reproduce a
bug I get with the clangd program (where a RealFileSystem is used).
This difference in behavior "hides" the bug in the unit test version.
An indirect impact of this change is that a -Wnonportable-include-path
warning is now emitted in test PCH/case-insensitive-include.c. This is
because the real path of the included file (with the wrong case) was not
available previously, whereas it is now.
Reviewers: malaperle, ilya-biryukov, bkramer
Reviewed By: ilya-biryukov
Subscribers: eric_niebler, malaperle, omtcyfz, hokein, bkramer, ilya-biryukov, ioeric, cfe-commits
Differential Revision: https://reviews.llvm.org/D48903
llvm-svn: 339063
2018-08-06 21:48:20 +00:00
|
|
|
std::string RequestedDirName;
|
|
|
|
|
|
|
|
void setCurrentEntry() {
|
|
|
|
if (I != E) {
|
|
|
|
SmallString<256> Path(RequestedDirName);
|
|
|
|
llvm::sys::path::append(Path, I->second->getFileName());
|
2019-11-04 17:23:07 +00:00
|
|
|
sys::fs::file_type Type = sys::fs::file_type::type_unknown;
|
2018-09-14 12:47:38 +00:00
|
|
|
switch (I->second->getKind()) {
|
2018-10-10 13:27:25 +00:00
|
|
|
case detail::IME_File:
|
|
|
|
case detail::IME_HardLink:
|
|
|
|
Type = sys::fs::file_type::regular_file;
|
|
|
|
break;
|
|
|
|
case detail::IME_Directory:
|
|
|
|
Type = sys::fs::file_type::directory_file;
|
|
|
|
break;
|
2022-06-21 10:20:24 +02:00
|
|
|
case detail::IME_SymbolicLink:
|
|
|
|
if (auto SymlinkTarget =
|
|
|
|
FS->lookupNode(Path, /*FollowFinalSymlink=*/true)) {
|
|
|
|
Path = SymlinkTarget.getName();
|
|
|
|
Type = (*SymlinkTarget)->getStatus(Path).getType();
|
|
|
|
}
|
|
|
|
break;
|
2018-09-14 12:47:38 +00:00
|
|
|
}
|
2024-01-17 20:22:58 -08:00
|
|
|
CurrentEntry = directory_entry(std::string(Path), Type);
|
[VirtualFileSystem] InMemoryFileSystem::status: Return a Status with the requested name
Summary:
InMemoryFileSystem::status behaves differently than
RealFileSystem::status. The Name contained in the Status returned by
RealFileSystem::status will be the path as requested by the caller,
whereas InMemoryFileSystem::status returns the normalized path.
For example, when requested the status for "../src/first.h",
RealFileSystem returns a Status with "../src/first.h" as the Name.
InMemoryFileSystem returns "/absolute/path/to/src/first.h".
The reason for this change is that I want to make a unit test in the
clangd testsuite (where we use an InMemoryFileSystem) to reproduce a
bug I get with the clangd program (where a RealFileSystem is used).
This difference in behavior "hides" the bug in the unit test version.
An indirect impact of this change is that a -Wnonportable-include-path
warning is now emitted in test PCH/case-insensitive-include.c. This is
because the real path of the included file (with the wrong case) was not
available previously, whereas it is now.
Reviewers: malaperle, ilya-biryukov, bkramer
Reviewed By: ilya-biryukov
Subscribers: eric_niebler, malaperle, omtcyfz, hokein, bkramer, ilya-biryukov, ioeric, cfe-commits
Differential Revision: https://reviews.llvm.org/D48903
llvm-svn: 339063
2018-08-06 21:48:20 +00:00
|
|
|
} else {
|
|
|
|
// When we're at the end, make CurrentEntry invalid and DirIterImpl will
|
|
|
|
// do the rest.
|
2018-09-14 12:47:38 +00:00
|
|
|
CurrentEntry = directory_entry();
|
[VirtualFileSystem] InMemoryFileSystem::status: Return a Status with the requested name
Summary:
InMemoryFileSystem::status behaves differently than
RealFileSystem::status. The Name contained in the Status returned by
RealFileSystem::status will be the path as requested by the caller,
whereas InMemoryFileSystem::status returns the normalized path.
For example, when requested the status for "../src/first.h",
RealFileSystem returns a Status with "../src/first.h" as the Name.
InMemoryFileSystem returns "/absolute/path/to/src/first.h".
The reason for this change is that I want to make a unit test in the
clangd testsuite (where we use an InMemoryFileSystem) to reproduce a
bug I get with the clangd program (where a RealFileSystem is used).
This difference in behavior "hides" the bug in the unit test version.
An indirect impact of this change is that a -Wnonportable-include-path
warning is now emitted in test PCH/case-insensitive-include.c. This is
because the real path of the included file (with the wrong case) was not
available previously, whereas it is now.
Reviewers: malaperle, ilya-biryukov, bkramer
Reviewed By: ilya-biryukov
Subscribers: eric_niebler, malaperle, omtcyfz, hokein, bkramer, ilya-biryukov, ioeric, cfe-commits
Differential Revision: https://reviews.llvm.org/D48903
llvm-svn: 339063
2018-08-06 21:48:20 +00:00
|
|
|
}
|
|
|
|
}
|
2015-10-05 13:55:14 +00:00
|
|
|
|
|
|
|
public:
|
2022-06-21 16:20:53 +02:00
|
|
|
DirIterator() = default;
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2022-06-21 10:20:24 +02:00
|
|
|
DirIterator(const InMemoryFileSystem *FS,
|
|
|
|
const detail::InMemoryDirectory &Dir,
|
|
|
|
std::string RequestedDirName)
|
|
|
|
: FS(FS), I(Dir.begin()), E(Dir.end()),
|
[VirtualFileSystem] InMemoryFileSystem::status: Return a Status with the requested name
Summary:
InMemoryFileSystem::status behaves differently than
RealFileSystem::status. The Name contained in the Status returned by
RealFileSystem::status will be the path as requested by the caller,
whereas InMemoryFileSystem::status returns the normalized path.
For example, when requested the status for "../src/first.h",
RealFileSystem returns a Status with "../src/first.h" as the Name.
InMemoryFileSystem returns "/absolute/path/to/src/first.h".
The reason for this change is that I want to make a unit test in the
clangd testsuite (where we use an InMemoryFileSystem) to reproduce a
bug I get with the clangd program (where a RealFileSystem is used).
This difference in behavior "hides" the bug in the unit test version.
An indirect impact of this change is that a -Wnonportable-include-path
warning is now emitted in test PCH/case-insensitive-include.c. This is
because the real path of the included file (with the wrong case) was not
available previously, whereas it is now.
Reviewers: malaperle, ilya-biryukov, bkramer
Reviewed By: ilya-biryukov
Subscribers: eric_niebler, malaperle, omtcyfz, hokein, bkramer, ilya-biryukov, ioeric, cfe-commits
Differential Revision: https://reviews.llvm.org/D48903
llvm-svn: 339063
2018-08-06 21:48:20 +00:00
|
|
|
RequestedDirName(std::move(RequestedDirName)) {
|
|
|
|
setCurrentEntry();
|
2015-10-05 13:55:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::error_code increment() override {
|
|
|
|
++I;
|
[VirtualFileSystem] InMemoryFileSystem::status: Return a Status with the requested name
Summary:
InMemoryFileSystem::status behaves differently than
RealFileSystem::status. The Name contained in the Status returned by
RealFileSystem::status will be the path as requested by the caller,
whereas InMemoryFileSystem::status returns the normalized path.
For example, when requested the status for "../src/first.h",
RealFileSystem returns a Status with "../src/first.h" as the Name.
InMemoryFileSystem returns "/absolute/path/to/src/first.h".
The reason for this change is that I want to make a unit test in the
clangd testsuite (where we use an InMemoryFileSystem) to reproduce a
bug I get with the clangd program (where a RealFileSystem is used).
This difference in behavior "hides" the bug in the unit test version.
An indirect impact of this change is that a -Wnonportable-include-path
warning is now emitted in test PCH/case-insensitive-include.c. This is
because the real path of the included file (with the wrong case) was not
available previously, whereas it is now.
Reviewers: malaperle, ilya-biryukov, bkramer
Reviewed By: ilya-biryukov
Subscribers: eric_niebler, malaperle, omtcyfz, hokein, bkramer, ilya-biryukov, ioeric, cfe-commits
Differential Revision: https://reviews.llvm.org/D48903
llvm-svn: 339063
2018-08-06 21:48:20 +00:00
|
|
|
setCurrentEntry();
|
2018-03-28 22:09:09 +00:00
|
|
|
return {};
|
2015-10-05 13:55:14 +00:00
|
|
|
}
|
|
|
|
};
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2015-10-05 13:55:14 +00:00
|
|
|
directory_iterator InMemoryFileSystem::dir_begin(const Twine &Dir,
|
|
|
|
std::error_code &EC) {
|
2022-06-21 10:20:24 +02:00
|
|
|
auto Node = lookupNode(Dir, /*FollowFinalSymlink=*/true);
|
2015-10-05 13:55:14 +00:00
|
|
|
if (!Node) {
|
|
|
|
EC = Node.getError();
|
2022-06-21 16:20:53 +02:00
|
|
|
return directory_iterator(std::make_shared<DirIterator>());
|
2015-10-05 13:55:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (auto *DirNode = dyn_cast<detail::InMemoryDirectory>(*Node))
|
[VirtualFileSystem] InMemoryFileSystem::status: Return a Status with the requested name
Summary:
InMemoryFileSystem::status behaves differently than
RealFileSystem::status. The Name contained in the Status returned by
RealFileSystem::status will be the path as requested by the caller,
whereas InMemoryFileSystem::status returns the normalized path.
For example, when requested the status for "../src/first.h",
RealFileSystem returns a Status with "../src/first.h" as the Name.
InMemoryFileSystem returns "/absolute/path/to/src/first.h".
The reason for this change is that I want to make a unit test in the
clangd testsuite (where we use an InMemoryFileSystem) to reproduce a
bug I get with the clangd program (where a RealFileSystem is used).
This difference in behavior "hides" the bug in the unit test version.
An indirect impact of this change is that a -Wnonportable-include-path
warning is now emitted in test PCH/case-insensitive-include.c. This is
because the real path of the included file (with the wrong case) was not
available previously, whereas it is now.
Reviewers: malaperle, ilya-biryukov, bkramer
Reviewed By: ilya-biryukov
Subscribers: eric_niebler, malaperle, omtcyfz, hokein, bkramer, ilya-biryukov, ioeric, cfe-commits
Differential Revision: https://reviews.llvm.org/D48903
llvm-svn: 339063
2018-08-06 21:48:20 +00:00
|
|
|
return directory_iterator(
|
2022-06-21 10:20:24 +02:00
|
|
|
std::make_shared<DirIterator>(this, *DirNode, Dir.str()));
|
2015-10-05 13:55:14 +00:00
|
|
|
|
|
|
|
EC = make_error_code(llvm::errc::not_a_directory);
|
2022-06-21 16:20:53 +02:00
|
|
|
return directory_iterator(std::make_shared<DirIterator>());
|
2015-10-05 13:55:14 +00:00
|
|
|
}
|
2016-01-09 16:33:16 +00:00
|
|
|
|
|
|
|
std::error_code InMemoryFileSystem::setCurrentWorkingDirectory(const Twine &P) {
|
|
|
|
SmallString<128> Path;
|
|
|
|
P.toVector(Path);
|
|
|
|
|
|
|
|
// Fix up relative paths. This just prepends the current working directory.
|
|
|
|
std::error_code EC = makeAbsolute(Path);
|
|
|
|
assert(!EC);
|
|
|
|
(void)EC;
|
|
|
|
|
|
|
|
if (useNormalizedPaths())
|
|
|
|
llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
|
|
|
|
|
|
|
|
if (!Path.empty())
|
2024-01-17 20:22:58 -08:00
|
|
|
WorkingDirectory = std::string(Path);
|
2018-03-28 22:09:09 +00:00
|
|
|
return {};
|
2015-10-05 13:55:14 +00:00
|
|
|
}
|
|
|
|
|
2024-04-12 10:09:04 -07:00
|
|
|
std::error_code InMemoryFileSystem::getRealPath(const Twine &Path,
|
|
|
|
SmallVectorImpl<char> &Output) {
|
2018-05-24 11:17:00 +00:00
|
|
|
auto CWD = getCurrentWorkingDirectory();
|
|
|
|
if (!CWD || CWD->empty())
|
|
|
|
return errc::operation_not_permitted;
|
|
|
|
Path.toVector(Output);
|
|
|
|
if (auto EC = makeAbsolute(Output))
|
|
|
|
return EC;
|
|
|
|
llvm::sys::path::remove_dots(Output, /*remove_dot_dot=*/true);
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2018-11-08 00:01:32 +00:00
|
|
|
std::error_code InMemoryFileSystem::isLocal(const Twine &Path, bool &Result) {
|
|
|
|
Result = false;
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2022-03-09 12:23:22 -08:00
|
|
|
void InMemoryFileSystem::printImpl(raw_ostream &OS, PrintType PrintContents,
|
|
|
|
unsigned IndentLevel) const {
|
|
|
|
printIndent(OS, IndentLevel);
|
|
|
|
OS << "InMemoryFileSystem\n";
|
|
|
|
}
|
|
|
|
|
2018-03-28 22:09:09 +00:00
|
|
|
} // namespace vfs
|
2018-10-10 13:27:25 +00:00
|
|
|
} // namespace llvm
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2014-02-21 23:39:37 +00:00
|
|
|
//===-----------------------------------------------------------------------===/
|
2015-10-07 10:05:44 +00:00
|
|
|
// RedirectingFileSystem implementation
|
2014-02-21 23:39:37 +00:00
|
|
|
//===-----------------------------------------------------------------------===/
|
|
|
|
|
2020-01-21 16:45:51 -08:00
|
|
|
namespace {
|
|
|
|
|
2021-01-15 17:33:52 +10:00
|
|
|
static llvm::sys::path::Style getExistingStyle(llvm::StringRef Path) {
|
|
|
|
// Detect the path style in use by checking the first separator.
|
2020-01-21 16:45:51 -08:00
|
|
|
llvm::sys::path::Style style = llvm::sys::path::Style::native;
|
|
|
|
const size_t n = Path.find_first_of("/\\");
|
2021-10-08 10:41:46 +00:00
|
|
|
// Can't distinguish between posix and windows_slash here.
|
2020-01-21 16:45:51 -08:00
|
|
|
if (n != static_cast<size_t>(-1))
|
|
|
|
style = (Path[n] == '/') ? llvm::sys::path::Style::posix
|
2021-10-08 10:41:46 +00:00
|
|
|
: llvm::sys::path::Style::windows_backslash;
|
2021-01-15 17:33:52 +10:00
|
|
|
return style;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Removes leading "./" as well as path components like ".." and ".".
|
|
|
|
static llvm::SmallString<256> canonicalize(llvm::StringRef Path) {
|
|
|
|
// First detect the path style in use by checking the first separator.
|
|
|
|
llvm::sys::path::Style style = getExistingStyle(Path);
|
2020-01-21 16:45:51 -08:00
|
|
|
|
|
|
|
// Now remove the dots. Explicitly specifying the path style prevents the
|
|
|
|
// direction of the slashes from changing.
|
|
|
|
llvm::SmallString<256> result =
|
|
|
|
llvm::sys::path::remove_leading_dotslash(Path, style);
|
|
|
|
llvm::sys::path::remove_dots(result, /*remove_dot_dot=*/true, style);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-02-03 12:53:22 -08:00
|
|
|
/// Whether the error and entry specify a file/directory that was not found.
|
|
|
|
static bool isFileNotFound(std::error_code EC,
|
|
|
|
RedirectingFileSystem::Entry *E = nullptr) {
|
|
|
|
if (E && !isa<RedirectingFileSystem::DirectoryRemapEntry>(E))
|
|
|
|
return false;
|
|
|
|
return EC == llvm::errc::no_such_file_or_directory;
|
|
|
|
}
|
|
|
|
|
2020-01-21 16:45:51 -08:00
|
|
|
} // anonymous namespace
|
|
|
|
|
|
|
|
|
2019-10-15 23:08:57 +00:00
|
|
|
RedirectingFileSystem::RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> FS)
|
|
|
|
: ExternalFS(std::move(FS)) {
|
|
|
|
if (ExternalFS)
|
|
|
|
if (auto ExternalWorkingDirectory =
|
|
|
|
ExternalFS->getCurrentWorkingDirectory()) {
|
|
|
|
WorkingDirectory = *ExternalWorkingDirectory;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-16 11:44:14 +10:00
|
|
|
/// Directory iterator implementation for \c RedirectingFileSystem's
|
|
|
|
/// directory entries.
|
|
|
|
class llvm::vfs::RedirectingFSDirIterImpl
|
2019-01-15 22:36:41 +00:00
|
|
|
: public llvm::vfs::detail::DirIterImpl {
|
2014-06-24 19:37:16 +00:00
|
|
|
std::string Dir;
|
2021-01-16 11:44:14 +10:00
|
|
|
RedirectingFileSystem::DirectoryEntry::iterator Current, End;
|
2018-10-26 22:14:33 +00:00
|
|
|
|
2021-01-16 11:44:14 +10:00
|
|
|
std::error_code incrementImpl(bool IsFirstTime) {
|
|
|
|
assert((IsFirstTime || Current != End) && "cannot iterate past end");
|
|
|
|
if (!IsFirstTime)
|
|
|
|
++Current;
|
|
|
|
if (Current != End) {
|
|
|
|
SmallString<128> PathStr(Dir);
|
|
|
|
llvm::sys::path::append(PathStr, (*Current)->getName());
|
|
|
|
sys::fs::file_type Type = sys::fs::file_type::type_unknown;
|
|
|
|
switch ((*Current)->getKind()) {
|
|
|
|
case RedirectingFileSystem::EK_Directory:
|
2022-08-08 11:24:15 -07:00
|
|
|
[[fallthrough]];
|
2021-01-15 17:33:52 +10:00
|
|
|
case RedirectingFileSystem::EK_DirectoryRemap:
|
2021-01-16 11:44:14 +10:00
|
|
|
Type = sys::fs::file_type::directory_file;
|
|
|
|
break;
|
|
|
|
case RedirectingFileSystem::EK_File:
|
|
|
|
Type = sys::fs::file_type::regular_file;
|
|
|
|
break;
|
|
|
|
}
|
2024-01-17 20:22:58 -08:00
|
|
|
CurrentEntry = directory_entry(std::string(PathStr), Type);
|
2021-01-16 11:44:14 +10:00
|
|
|
} else {
|
|
|
|
CurrentEntry = directory_entry();
|
|
|
|
}
|
|
|
|
return {};
|
|
|
|
};
|
2018-08-07 23:00:40 +00:00
|
|
|
|
2014-06-24 19:37:16 +00:00
|
|
|
public:
|
2021-01-16 11:44:14 +10:00
|
|
|
RedirectingFSDirIterImpl(
|
|
|
|
const Twine &Path, RedirectingFileSystem::DirectoryEntry::iterator Begin,
|
|
|
|
RedirectingFileSystem::DirectoryEntry::iterator End, std::error_code &EC)
|
|
|
|
: Dir(Path.str()), Current(Begin), End(End) {
|
|
|
|
EC = incrementImpl(/*IsFirstTime=*/true);
|
|
|
|
}
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2021-01-16 11:44:14 +10:00
|
|
|
std::error_code increment() override {
|
|
|
|
return incrementImpl(/*IsFirstTime=*/false);
|
|
|
|
}
|
2014-06-24 19:37:16 +00:00
|
|
|
};
|
|
|
|
|
2021-11-07 15:18:30 +01:00
|
|
|
namespace {
|
2021-01-15 17:33:52 +10:00
|
|
|
/// Directory iterator implementation for \c RedirectingFileSystem's
|
|
|
|
/// directory remap entries that maps the paths reported by the external
|
|
|
|
/// file system's directory iterator back to the virtual directory's path.
|
|
|
|
class RedirectingFSDirRemapIterImpl : public llvm::vfs::detail::DirIterImpl {
|
|
|
|
std::string Dir;
|
|
|
|
llvm::sys::path::Style DirStyle;
|
|
|
|
llvm::vfs::directory_iterator ExternalIter;
|
|
|
|
|
|
|
|
public:
|
|
|
|
RedirectingFSDirRemapIterImpl(std::string DirPath,
|
|
|
|
llvm::vfs::directory_iterator ExtIter)
|
|
|
|
: Dir(std::move(DirPath)), DirStyle(getExistingStyle(Dir)),
|
|
|
|
ExternalIter(ExtIter) {
|
|
|
|
if (ExternalIter != llvm::vfs::directory_iterator())
|
|
|
|
setCurrentEntry();
|
|
|
|
}
|
|
|
|
|
|
|
|
void setCurrentEntry() {
|
|
|
|
StringRef ExternalPath = ExternalIter->path();
|
|
|
|
llvm::sys::path::Style ExternalStyle = getExistingStyle(ExternalPath);
|
|
|
|
StringRef File = llvm::sys::path::filename(ExternalPath, ExternalStyle);
|
|
|
|
|
|
|
|
SmallString<128> NewPath(Dir);
|
|
|
|
llvm::sys::path::append(NewPath, DirStyle, File);
|
|
|
|
|
|
|
|
CurrentEntry = directory_entry(std::string(NewPath), ExternalIter->type());
|
|
|
|
}
|
|
|
|
|
|
|
|
std::error_code increment() override {
|
|
|
|
std::error_code EC;
|
|
|
|
ExternalIter.increment(EC);
|
|
|
|
if (!EC && ExternalIter != llvm::vfs::directory_iterator())
|
|
|
|
setCurrentEntry();
|
|
|
|
else
|
|
|
|
CurrentEntry = directory_entry();
|
|
|
|
return EC;
|
|
|
|
}
|
|
|
|
};
|
2021-11-07 15:18:30 +01:00
|
|
|
} // namespace
|
2021-01-15 17:33:52 +10:00
|
|
|
|
2019-01-15 22:36:41 +00:00
|
|
|
llvm::ErrorOr<std::string>
|
|
|
|
RedirectingFileSystem::getCurrentWorkingDirectory() const {
|
2019-10-15 23:08:57 +00:00
|
|
|
return WorkingDirectory;
|
2019-01-15 22:36:41 +00:00
|
|
|
}
|
2014-02-21 23:39:37 +00:00
|
|
|
|
2019-01-15 22:36:41 +00:00
|
|
|
std::error_code
|
|
|
|
RedirectingFileSystem::setCurrentWorkingDirectory(const Twine &Path) {
|
2019-10-15 23:08:57 +00:00
|
|
|
// Don't change the working directory if the path doesn't exist.
|
|
|
|
if (!exists(Path))
|
|
|
|
return errc::no_such_file_or_directory;
|
|
|
|
|
|
|
|
SmallString<128> AbsolutePath;
|
|
|
|
Path.toVector(AbsolutePath);
|
|
|
|
if (std::error_code EC = makeAbsolute(AbsolutePath))
|
|
|
|
return EC;
|
2024-01-17 20:22:58 -08:00
|
|
|
WorkingDirectory = std::string(AbsolutePath);
|
2019-10-15 23:08:57 +00:00
|
|
|
return {};
|
2019-01-15 22:36:41 +00:00
|
|
|
}
|
2014-06-24 19:37:16 +00:00
|
|
|
|
2021-01-22 13:51:59 -08:00
|
|
|
std::error_code RedirectingFileSystem::isLocal(const Twine &Path_,
|
2019-01-15 22:36:41 +00:00
|
|
|
bool &Result) {
|
2021-01-22 13:51:59 -08:00
|
|
|
SmallString<256> Path;
|
|
|
|
Path_.toVector(Path);
|
|
|
|
|
2024-03-15 09:01:41 -07:00
|
|
|
if (makeAbsolute(Path))
|
2021-01-22 13:51:59 -08:00
|
|
|
return {};
|
|
|
|
|
2019-01-15 22:36:41 +00:00
|
|
|
return ExternalFS->isLocal(Path, Result);
|
|
|
|
}
|
2018-11-16 01:15:54 +00:00
|
|
|
|
2019-11-25 15:57:21 -08:00
|
|
|
std::error_code RedirectingFileSystem::makeAbsolute(SmallVectorImpl<char> &Path) const {
|
2021-10-08 10:41:46 +00:00
|
|
|
// is_absolute(..., Style::windows_*) accepts paths with both slash types.
|
2019-11-25 15:57:21 -08:00
|
|
|
if (llvm::sys::path::is_absolute(Path, llvm::sys::path::Style::posix) ||
|
2021-10-08 10:41:46 +00:00
|
|
|
llvm::sys::path::is_absolute(Path,
|
|
|
|
llvm::sys::path::Style::windows_backslash))
|
2022-11-04 16:40:10 -07:00
|
|
|
// This covers windows absolute path with forward slash as well, as the
|
2024-06-13 20:20:27 +01:00
|
|
|
// forward slashes are treated as path separation in llvm::path
|
2022-11-04 16:40:10 -07:00
|
|
|
// regardless of what path::Style is used.
|
2019-11-25 15:57:21 -08:00
|
|
|
return {};
|
|
|
|
|
|
|
|
auto WorkingDir = getCurrentWorkingDirectory();
|
|
|
|
if (!WorkingDir)
|
|
|
|
return WorkingDir.getError();
|
|
|
|
|
2022-11-04 16:40:10 -07:00
|
|
|
return makeAbsolute(WorkingDir.get(), Path);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::error_code
|
|
|
|
RedirectingFileSystem::makeAbsolute(StringRef WorkingDir,
|
|
|
|
SmallVectorImpl<char> &Path) const {
|
2020-01-21 16:45:51 -08:00
|
|
|
// We can't use sys::fs::make_absolute because that assumes the path style
|
|
|
|
// is native and there is no way to override that. Since we know WorkingDir
|
|
|
|
// is absolute, we can use it to determine which style we actually have and
|
|
|
|
// append Path ourselves.
|
2022-11-04 16:40:10 -07:00
|
|
|
if (!WorkingDir.empty() &&
|
|
|
|
!sys::path::is_absolute(WorkingDir, sys::path::Style::posix) &&
|
|
|
|
!sys::path::is_absolute(WorkingDir,
|
|
|
|
sys::path::Style::windows_backslash)) {
|
|
|
|
return std::error_code();
|
|
|
|
}
|
2021-10-08 10:41:46 +00:00
|
|
|
sys::path::Style style = sys::path::Style::windows_backslash;
|
2022-11-04 16:40:10 -07:00
|
|
|
if (sys::path::is_absolute(WorkingDir, sys::path::Style::posix)) {
|
2020-01-21 16:45:51 -08:00
|
|
|
style = sys::path::Style::posix;
|
2021-10-08 10:41:46 +00:00
|
|
|
} else {
|
|
|
|
// Distinguish between windows_backslash and windows_slash; getExistingStyle
|
|
|
|
// returns posix for a path with windows_slash.
|
2022-11-04 16:40:10 -07:00
|
|
|
if (getExistingStyle(WorkingDir) != sys::path::Style::windows_backslash)
|
2021-10-08 10:41:46 +00:00
|
|
|
style = sys::path::Style::windows_slash;
|
2020-01-21 16:45:51 -08:00
|
|
|
}
|
|
|
|
|
2022-11-04 16:40:10 -07:00
|
|
|
std::string Result = std::string(WorkingDir);
|
2020-01-21 16:45:51 -08:00
|
|
|
StringRef Dir(Result);
|
2023-11-03 18:14:49 +00:00
|
|
|
if (!Dir.ends_with(sys::path::get_separator(style))) {
|
2020-01-21 16:45:51 -08:00
|
|
|
Result += sys::path::get_separator(style);
|
|
|
|
}
|
2022-11-04 16:40:10 -07:00
|
|
|
// backslashes '\' are legit path charactors under POSIX. Windows APIs
|
|
|
|
// like CreateFile accepts forward slashes '/' as path
|
|
|
|
// separator (even when mixed with backslashes). Therefore,
|
|
|
|
// `Path` should be directly appended to `WorkingDir` without converting
|
|
|
|
// path separator.
|
2020-01-21 16:45:51 -08:00
|
|
|
Result.append(Path.data(), Path.size());
|
|
|
|
Path.assign(Result.begin(), Result.end());
|
|
|
|
|
2019-11-25 15:57:21 -08:00
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2019-01-15 22:36:41 +00:00
|
|
|
directory_iterator RedirectingFileSystem::dir_begin(const Twine &Dir,
|
|
|
|
std::error_code &EC) {
|
2021-01-22 13:51:59 -08:00
|
|
|
SmallString<256> Path;
|
|
|
|
Dir.toVector(Path);
|
|
|
|
|
2024-03-15 09:01:41 -07:00
|
|
|
EC = makeAbsolute(Path);
|
2021-01-22 13:51:59 -08:00
|
|
|
if (EC)
|
|
|
|
return {};
|
|
|
|
|
2021-01-15 17:33:52 +10:00
|
|
|
ErrorOr<RedirectingFileSystem::LookupResult> Result = lookupPath(Path);
|
|
|
|
if (!Result) {
|
2022-02-03 12:53:22 -08:00
|
|
|
if (Redirection != RedirectKind::RedirectOnly &&
|
|
|
|
isFileNotFound(Result.getError()))
|
2021-01-22 13:51:59 -08:00
|
|
|
return ExternalFS->dir_begin(Path, EC);
|
2022-02-03 12:53:22 -08:00
|
|
|
|
|
|
|
EC = Result.getError();
|
2019-01-15 22:36:41 +00:00
|
|
|
return {};
|
2015-10-05 13:55:20 +00:00
|
|
|
}
|
2021-01-15 17:33:52 +10:00
|
|
|
|
|
|
|
// Use status to make sure the path exists and refers to a directory.
|
2021-11-13 10:13:38 -08:00
|
|
|
ErrorOr<Status> S = status(Path, Dir, *Result);
|
2019-01-15 22:36:41 +00:00
|
|
|
if (!S) {
|
2022-02-03 12:53:22 -08:00
|
|
|
if (Redirection != RedirectKind::RedirectOnly &&
|
|
|
|
isFileNotFound(S.getError(), Result->E))
|
2021-01-15 17:33:52 +10:00
|
|
|
return ExternalFS->dir_begin(Dir, EC);
|
2022-02-03 12:53:22 -08:00
|
|
|
|
2019-01-15 22:36:41 +00:00
|
|
|
EC = S.getError();
|
|
|
|
return {};
|
2015-10-05 13:55:20 +00:00
|
|
|
}
|
2022-02-03 12:53:22 -08:00
|
|
|
|
2019-01-15 22:36:41 +00:00
|
|
|
if (!S->isDirectory()) {
|
2022-02-21 21:13:38 -08:00
|
|
|
EC = errc::not_a_directory;
|
2019-01-15 22:36:41 +00:00
|
|
|
return {};
|
2018-11-08 00:01:32 +00:00
|
|
|
}
|
|
|
|
|
2021-01-15 17:33:52 +10:00
|
|
|
// Create the appropriate directory iterator based on whether we found a
|
|
|
|
// DirectoryRemapEntry or DirectoryEntry.
|
2022-02-03 12:53:22 -08:00
|
|
|
directory_iterator RedirectIter;
|
|
|
|
std::error_code RedirectEC;
|
2021-01-15 17:33:52 +10:00
|
|
|
if (auto ExtRedirect = Result->getExternalRedirect()) {
|
|
|
|
auto RE = cast<RedirectingFileSystem::RemapEntry>(Result->E);
|
2022-02-03 12:53:22 -08:00
|
|
|
RedirectIter = ExternalFS->dir_begin(*ExtRedirect, RedirectEC);
|
2021-01-15 17:33:52 +10:00
|
|
|
|
|
|
|
if (!RE->useExternalName(UseExternalNames)) {
|
|
|
|
// Update the paths in the results to use the virtual directory's path.
|
2022-02-03 12:53:22 -08:00
|
|
|
RedirectIter =
|
2021-01-15 17:33:52 +10:00
|
|
|
directory_iterator(std::make_shared<RedirectingFSDirRemapIterImpl>(
|
2022-02-03 12:53:22 -08:00
|
|
|
std::string(Path), RedirectIter));
|
2021-01-15 17:33:52 +10:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
auto DE = cast<DirectoryEntry>(Result->E);
|
2022-02-03 12:53:22 -08:00
|
|
|
RedirectIter =
|
|
|
|
directory_iterator(std::make_shared<RedirectingFSDirIterImpl>(
|
|
|
|
Path, DE->contents_begin(), DE->contents_end(), RedirectEC));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (RedirectEC) {
|
|
|
|
if (RedirectEC != errc::no_such_file_or_directory) {
|
|
|
|
EC = RedirectEC;
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
RedirectIter = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Redirection == RedirectKind::RedirectOnly) {
|
|
|
|
EC = RedirectEC;
|
|
|
|
return RedirectIter;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::error_code ExternalEC;
|
|
|
|
directory_iterator ExternalIter = ExternalFS->dir_begin(Path, ExternalEC);
|
|
|
|
if (ExternalEC) {
|
|
|
|
if (ExternalEC != errc::no_such_file_or_directory) {
|
|
|
|
EC = ExternalEC;
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
ExternalIter = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
SmallVector<directory_iterator, 2> Iters;
|
|
|
|
switch (Redirection) {
|
|
|
|
case RedirectKind::Fallthrough:
|
|
|
|
Iters.push_back(ExternalIter);
|
|
|
|
Iters.push_back(RedirectIter);
|
|
|
|
break;
|
|
|
|
case RedirectKind::Fallback:
|
|
|
|
Iters.push_back(RedirectIter);
|
|
|
|
Iters.push_back(ExternalIter);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
llvm_unreachable("unhandled RedirectKind");
|
2021-01-15 17:33:52 +10:00
|
|
|
}
|
2021-01-16 11:44:14 +10:00
|
|
|
|
2022-02-03 12:53:22 -08:00
|
|
|
directory_iterator Combined{
|
|
|
|
std::make_shared<CombiningDirIterImpl>(Iters, EC)};
|
|
|
|
if (EC)
|
|
|
|
return {};
|
|
|
|
return Combined;
|
2019-01-15 22:36:41 +00:00
|
|
|
}
|
Reapply [2] [VFS] Add 'overlay-relative' field to YAML files
This reapplies r261552 and r263748. Fixed testcase to reapply.
The VFS overlay mapping between virtual paths and real paths is done through
the 'external-contents' entries in YAML files, which contains hardcoded paths
to the real files.
When a module compilation crashes, headers are dumped into <name>.cache/vfs
directory and are mapped via the <name>.cache/vfs/vfs.yaml. The script
generated for reproduction uses -ivfsoverlay pointing to file to gather the
mapping between virtual paths and files inside <name>.cache/vfs. Currently, we
are only capable of reproducing such crashes in the same machine as they
happen, because of the hardcoded paths in 'external-contents'.
To be able to reproduce a crash in another machine, this patch introduces a new
option in the VFS yaml file called 'overlay-relative'. When it's equal to
'true' it means that the provided path to the YAML file through the
-ivfsoverlay option should also be used to prefix the final path for every
'external-contents'.
Example, given the invocation snippet "... -ivfsoverlay
<name>.cache/vfs/vfs.yaml" and the following entry in the yaml file:
"overlay-relative": "true",
"roots": [
...
"type": "directory",
"name": "/usr/include",
"contents": [
{
"type": "file",
"name": "stdio.h",
"external-contents": "/usr/include/stdio.h"
},
...
Here, a file manager request for virtual "/usr/include/stdio.h", that will map
into real path "/<absolute_path_to>/<name>.cache/vfs/usr/include/stdio.h.
This is a useful feature for debugging module crashes in machines other than
the one where the error happened.
Differential Revision: http://reviews.llvm.org/D17457
rdar://problem/24499339
llvm-svn: 263893
2016-03-20 02:08:48 +00:00
|
|
|
|
2022-11-04 16:40:10 -07:00
|
|
|
void RedirectingFileSystem::setOverlayFileDir(StringRef Dir) {
|
|
|
|
OverlayFileDir = Dir.str();
|
2019-01-15 22:36:41 +00:00
|
|
|
}
|
Reapply [2] [VFS] Add 'overlay-relative' field to YAML files
This reapplies r261552 and r263748. Fixed testcase to reapply.
The VFS overlay mapping between virtual paths and real paths is done through
the 'external-contents' entries in YAML files, which contains hardcoded paths
to the real files.
When a module compilation crashes, headers are dumped into <name>.cache/vfs
directory and are mapped via the <name>.cache/vfs/vfs.yaml. The script
generated for reproduction uses -ivfsoverlay pointing to file to gather the
mapping between virtual paths and files inside <name>.cache/vfs. Currently, we
are only capable of reproducing such crashes in the same machine as they
happen, because of the hardcoded paths in 'external-contents'.
To be able to reproduce a crash in another machine, this patch introduces a new
option in the VFS yaml file called 'overlay-relative'. When it's equal to
'true' it means that the provided path to the YAML file through the
-ivfsoverlay option should also be used to prefix the final path for every
'external-contents'.
Example, given the invocation snippet "... -ivfsoverlay
<name>.cache/vfs/vfs.yaml" and the following entry in the yaml file:
"overlay-relative": "true",
"roots": [
...
"type": "directory",
"name": "/usr/include",
"contents": [
{
"type": "file",
"name": "stdio.h",
"external-contents": "/usr/include/stdio.h"
},
...
Here, a file manager request for virtual "/usr/include/stdio.h", that will map
into real path "/<absolute_path_to>/<name>.cache/vfs/usr/include/stdio.h.
This is a useful feature for debugging module crashes in machines other than
the one where the error happened.
Differential Revision: http://reviews.llvm.org/D17457
rdar://problem/24499339
llvm-svn: 263893
2016-03-20 02:08:48 +00:00
|
|
|
|
2022-11-04 16:40:10 -07:00
|
|
|
StringRef RedirectingFileSystem::getOverlayFileDir() const {
|
|
|
|
return OverlayFileDir;
|
2019-01-15 22:36:41 +00:00
|
|
|
}
|
Reapply [2] [VFS] Add 'overlay-relative' field to YAML files
This reapplies r261552 and r263748. Fixed testcase to reapply.
The VFS overlay mapping between virtual paths and real paths is done through
the 'external-contents' entries in YAML files, which contains hardcoded paths
to the real files.
When a module compilation crashes, headers are dumped into <name>.cache/vfs
directory and are mapped via the <name>.cache/vfs/vfs.yaml. The script
generated for reproduction uses -ivfsoverlay pointing to file to gather the
mapping between virtual paths and files inside <name>.cache/vfs. Currently, we
are only capable of reproducing such crashes in the same machine as they
happen, because of the hardcoded paths in 'external-contents'.
To be able to reproduce a crash in another machine, this patch introduces a new
option in the VFS yaml file called 'overlay-relative'. When it's equal to
'true' it means that the provided path to the YAML file through the
-ivfsoverlay option should also be used to prefix the final path for every
'external-contents'.
Example, given the invocation snippet "... -ivfsoverlay
<name>.cache/vfs/vfs.yaml" and the following entry in the yaml file:
"overlay-relative": "true",
"roots": [
...
"type": "directory",
"name": "/usr/include",
"contents": [
{
"type": "file",
"name": "stdio.h",
"external-contents": "/usr/include/stdio.h"
},
...
Here, a file manager request for virtual "/usr/include/stdio.h", that will map
into real path "/<absolute_path_to>/<name>.cache/vfs/usr/include/stdio.h.
This is a useful feature for debugging module crashes in machines other than
the one where the error happened.
Differential Revision: http://reviews.llvm.org/D17457
rdar://problem/24499339
llvm-svn: 263893
2016-03-20 02:08:48 +00:00
|
|
|
|
2022-02-03 13:35:16 -08:00
|
|
|
void RedirectingFileSystem::setFallthrough(bool Fallthrough) {
|
|
|
|
if (Fallthrough) {
|
|
|
|
Redirection = RedirectingFileSystem::RedirectKind::Fallthrough;
|
|
|
|
} else {
|
|
|
|
Redirection = RedirectingFileSystem::RedirectKind::RedirectOnly;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-03 12:53:22 -08:00
|
|
|
void RedirectingFileSystem::setRedirection(
|
|
|
|
RedirectingFileSystem::RedirectKind Kind) {
|
|
|
|
Redirection = Kind;
|
2020-08-31 15:13:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<StringRef> RedirectingFileSystem::getRoots() const {
|
|
|
|
std::vector<StringRef> R;
|
2022-12-08 08:42:50 +00:00
|
|
|
R.reserve(Roots.size());
|
2020-08-31 15:13:49 -07:00
|
|
|
for (const auto &Root : Roots)
|
|
|
|
R.push_back(Root->getName());
|
|
|
|
return R;
|
|
|
|
}
|
|
|
|
|
2022-03-09 12:23:22 -08:00
|
|
|
void RedirectingFileSystem::printImpl(raw_ostream &OS, PrintType Type,
|
|
|
|
unsigned IndentLevel) const {
|
|
|
|
printIndent(OS, IndentLevel);
|
|
|
|
OS << "RedirectingFileSystem (UseExternalNames: "
|
|
|
|
<< (UseExternalNames ? "true" : "false") << ")\n";
|
|
|
|
if (Type == PrintType::Summary)
|
|
|
|
return;
|
|
|
|
|
2019-01-15 22:36:41 +00:00
|
|
|
for (const auto &Root : Roots)
|
2022-03-09 12:23:22 -08:00
|
|
|
printEntry(OS, Root.get(), IndentLevel);
|
|
|
|
|
|
|
|
printIndent(OS, IndentLevel);
|
|
|
|
OS << "ExternalFS:\n";
|
|
|
|
ExternalFS->print(OS, Type == PrintType::Contents ? PrintType::Summary : Type,
|
|
|
|
IndentLevel + 1);
|
2019-01-15 22:36:41 +00:00
|
|
|
}
|
2016-05-06 23:21:57 +00:00
|
|
|
|
2022-03-11 14:31:21 -08:00
|
|
|
void RedirectingFileSystem::printEntry(raw_ostream &OS,
|
|
|
|
RedirectingFileSystem::Entry *E,
|
2022-03-09 12:23:22 -08:00
|
|
|
unsigned IndentLevel) const {
|
|
|
|
printIndent(OS, IndentLevel);
|
|
|
|
OS << "'" << E->getName() << "'";
|
2016-05-06 23:21:57 +00:00
|
|
|
|
2022-03-09 12:23:22 -08:00
|
|
|
switch (E->getKind()) {
|
|
|
|
case EK_Directory: {
|
|
|
|
auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(E);
|
2016-05-06 23:21:57 +00:00
|
|
|
|
2022-03-09 12:23:22 -08:00
|
|
|
OS << "\n";
|
2019-01-15 22:36:41 +00:00
|
|
|
for (std::unique_ptr<Entry> &SubEntry :
|
|
|
|
llvm::make_range(DE->contents_begin(), DE->contents_end()))
|
2022-03-09 12:23:22 -08:00
|
|
|
printEntry(OS, SubEntry.get(), IndentLevel + 1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case EK_DirectoryRemap:
|
|
|
|
case EK_File: {
|
|
|
|
auto *RE = cast<RedirectingFileSystem::RemapEntry>(E);
|
|
|
|
OS << " -> '" << RE->getExternalContentsPath() << "'";
|
|
|
|
switch (RE->getUseName()) {
|
|
|
|
case NK_NotSet:
|
|
|
|
break;
|
|
|
|
case NK_External:
|
|
|
|
OS << " (UseExternalName: true)";
|
|
|
|
break;
|
|
|
|
case NK_Virtual:
|
|
|
|
OS << " (UseExternalName: false)";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
OS << "\n";
|
|
|
|
break;
|
|
|
|
}
|
2016-05-06 23:21:57 +00:00
|
|
|
}
|
2019-01-15 22:36:41 +00:00
|
|
|
}
|
2019-09-13 23:27:31 +00:00
|
|
|
|
2024-01-30 15:39:18 -08:00
|
|
|
void RedirectingFileSystem::visitChildFileSystems(VisitCallbackTy Callback) {
|
|
|
|
if (ExternalFS) {
|
|
|
|
Callback(*ExternalFS);
|
|
|
|
ExternalFS->visitChildFileSystems(Callback);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-09 01:00:01 +00:00
|
|
|
/// A helper class to hold the common YAML parsing state.
|
2019-01-15 22:36:41 +00:00
|
|
|
class llvm::vfs::RedirectingFileSystemParser {
|
2014-02-21 23:39:37 +00:00
|
|
|
yaml::Stream &Stream;
|
|
|
|
|
2018-10-10 13:27:25 +00:00
|
|
|
void error(yaml::Node *N, const Twine &Msg) { Stream.printError(N, Msg); }
|
2014-02-21 23:39:37 +00:00
|
|
|
|
|
|
|
// false on error
|
|
|
|
bool parseScalarString(yaml::Node *N, StringRef &Result,
|
|
|
|
SmallVectorImpl<char> &Storage) {
|
2018-03-28 22:09:09 +00:00
|
|
|
const auto *S = dyn_cast<yaml::ScalarNode>(N);
|
|
|
|
|
2014-02-21 23:39:37 +00:00
|
|
|
if (!S) {
|
|
|
|
error(N, "expected string");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
Result = S->getValue(Storage);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// false on error
|
|
|
|
bool parseScalarBool(yaml::Node *N, bool &Result) {
|
|
|
|
SmallString<5> Storage;
|
|
|
|
StringRef Value;
|
|
|
|
if (!parseScalarString(N, Value, Storage))
|
|
|
|
return false;
|
|
|
|
|
2021-06-23 14:52:36 +03:00
|
|
|
if (Value.equals_insensitive("true") || Value.equals_insensitive("on") ||
|
|
|
|
Value.equals_insensitive("yes") || Value == "1") {
|
2014-02-21 23:39:37 +00:00
|
|
|
Result = true;
|
|
|
|
return true;
|
2021-06-23 14:52:36 +03:00
|
|
|
} else if (Value.equals_insensitive("false") ||
|
|
|
|
Value.equals_insensitive("off") ||
|
|
|
|
Value.equals_insensitive("no") || Value == "0") {
|
2014-02-21 23:39:37 +00:00
|
|
|
Result = false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
error(N, "expected boolean value");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-11-25 21:53:00 -08:00
|
|
|
std::optional<RedirectingFileSystem::RedirectKind>
|
2022-02-03 12:53:22 -08:00
|
|
|
parseRedirectKind(yaml::Node *N) {
|
|
|
|
SmallString<12> Storage;
|
|
|
|
StringRef Value;
|
|
|
|
if (!parseScalarString(N, Value, Storage))
|
2022-12-02 21:11:44 -08:00
|
|
|
return std::nullopt;
|
2022-02-03 12:53:22 -08:00
|
|
|
|
|
|
|
if (Value.equals_insensitive("fallthrough")) {
|
|
|
|
return RedirectingFileSystem::RedirectKind::Fallthrough;
|
|
|
|
} else if (Value.equals_insensitive("fallback")) {
|
|
|
|
return RedirectingFileSystem::RedirectKind::Fallback;
|
|
|
|
} else if (Value.equals_insensitive("redirect-only")) {
|
|
|
|
return RedirectingFileSystem::RedirectKind::RedirectOnly;
|
|
|
|
}
|
2022-12-02 21:11:44 -08:00
|
|
|
return std::nullopt;
|
2022-02-03 12:53:22 -08:00
|
|
|
}
|
|
|
|
|
2022-12-20 15:42:32 -08:00
|
|
|
std::optional<RedirectingFileSystem::RootRelativeKind>
|
2022-11-04 16:40:10 -07:00
|
|
|
parseRootRelativeKind(yaml::Node *N) {
|
|
|
|
SmallString<12> Storage;
|
|
|
|
StringRef Value;
|
|
|
|
if (!parseScalarString(N, Value, Storage))
|
|
|
|
return std::nullopt;
|
|
|
|
if (Value.equals_insensitive("cwd")) {
|
|
|
|
return RedirectingFileSystem::RootRelativeKind::CWD;
|
|
|
|
} else if (Value.equals_insensitive("overlay-dir")) {
|
|
|
|
return RedirectingFileSystem::RootRelativeKind::OverlayDir;
|
|
|
|
}
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
|
2014-02-21 23:39:37 +00:00
|
|
|
struct KeyStatus {
|
|
|
|
bool Required;
|
2018-03-28 22:09:09 +00:00
|
|
|
bool Seen = false;
|
|
|
|
|
|
|
|
KeyStatus(bool Required = false) : Required(Required) {}
|
2014-02-21 23:39:37 +00:00
|
|
|
};
|
2018-03-28 22:09:09 +00:00
|
|
|
|
|
|
|
using KeyStatusPair = std::pair<StringRef, KeyStatus>;
|
2014-02-21 23:39:37 +00:00
|
|
|
|
|
|
|
// false on error
|
|
|
|
bool checkDuplicateOrUnknownKey(yaml::Node *KeyNode, StringRef Key,
|
|
|
|
DenseMap<StringRef, KeyStatus> &Keys) {
|
|
|
|
if (!Keys.count(Key)) {
|
|
|
|
error(KeyNode, "unknown key");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
KeyStatus &S = Keys[Key];
|
|
|
|
if (S.Seen) {
|
|
|
|
error(KeyNode, Twine("duplicate key '") + Key + "'");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
S.Seen = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// false on error
|
|
|
|
bool checkMissingKeys(yaml::Node *Obj, DenseMap<StringRef, KeyStatus> &Keys) {
|
2018-03-28 22:09:09 +00:00
|
|
|
for (const auto &I : Keys) {
|
|
|
|
if (I.second.Required && !I.second.Seen) {
|
|
|
|
error(Obj, Twine("missing key '") + I.first + "'");
|
2014-02-21 23:39:37 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-11-11 23:03:38 -05:00
|
|
|
public:
|
|
|
|
static RedirectingFileSystem::Entry *
|
2019-01-15 22:36:41 +00:00
|
|
|
lookupOrCreateEntry(RedirectingFileSystem *FS, StringRef Name,
|
|
|
|
RedirectingFileSystem::Entry *ParentEntry = nullptr) {
|
[VFS] Reapply #2: Reconstruct the VFS overlay tree for more accurate lookup
Reapply r269100 and r269270, reverted due to
https://llvm.org/bugs/show_bug.cgi?id=27725. Isolate the testcase that
corresponds to the new feature side of this commit and skip it on
windows hosts until we find why it does not work on these platforms.
Original commit message:
The way we currently build the internal VFS overlay representation leads
to inefficient path search and might yield wrong answers when asked for
recursive or regular directory iteration.
Currently, when reading an YAML file, each YAML root entry is placed
inside a new root in the filesystem overlay. In the crash reproducer, a
simple "@import Foundation" currently maps to 43 roots, and when looking
up paths, we traverse a directory tree for each of these different
roots, until we find a match (or don't). This has two consequences:
- It's slow.
- Directory iteration gives incomplete results since it only return
results within one root - since contents of the same directory can be
declared inside different roots, the result isn't accurate.
This is in part fault of the way we currently write out the YAML file
when emitting the crash reproducer - we could generate only one root and
that would make it fast and correct again. However, we should not rely
on how the client writes the YAML, but provide a good internal
representation regardless.
Build a proper virtual directory tree out of the YAML representation,
allowing faster search and proper iteration. Besides the crash
reproducer, this potentially benefits other VFS clients.
llvm-svn: 269327
2016-05-12 19:13:07 +00:00
|
|
|
if (!ParentEntry) { // Look for a existent root
|
2018-03-28 22:09:09 +00:00
|
|
|
for (const auto &Root : FS->Roots) {
|
2024-05-08 10:33:53 -07:00
|
|
|
if (Name == Root->getName()) {
|
[VFS] Reapply #2: Reconstruct the VFS overlay tree for more accurate lookup
Reapply r269100 and r269270, reverted due to
https://llvm.org/bugs/show_bug.cgi?id=27725. Isolate the testcase that
corresponds to the new feature side of this commit and skip it on
windows hosts until we find why it does not work on these platforms.
Original commit message:
The way we currently build the internal VFS overlay representation leads
to inefficient path search and might yield wrong answers when asked for
recursive or regular directory iteration.
Currently, when reading an YAML file, each YAML root entry is placed
inside a new root in the filesystem overlay. In the crash reproducer, a
simple "@import Foundation" currently maps to 43 roots, and when looking
up paths, we traverse a directory tree for each of these different
roots, until we find a match (or don't). This has two consequences:
- It's slow.
- Directory iteration gives incomplete results since it only return
results within one root - since contents of the same directory can be
declared inside different roots, the result isn't accurate.
This is in part fault of the way we currently write out the YAML file
when emitting the crash reproducer - we could generate only one root and
that would make it fast and correct again. However, we should not rely
on how the client writes the YAML, but provide a good internal
representation regardless.
Build a proper virtual directory tree out of the YAML representation,
allowing faster search and proper iteration. Besides the crash
reproducer, this potentially benefits other VFS clients.
llvm-svn: 269327
2016-05-12 19:13:07 +00:00
|
|
|
ParentEntry = Root.get();
|
|
|
|
return ParentEntry;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else { // Advance to the next component
|
2021-01-16 11:44:14 +10:00
|
|
|
auto *DE = dyn_cast<RedirectingFileSystem::DirectoryEntry>(ParentEntry);
|
2019-01-15 22:36:41 +00:00
|
|
|
for (std::unique_ptr<RedirectingFileSystem::Entry> &Content :
|
[VFS] Reapply #2: Reconstruct the VFS overlay tree for more accurate lookup
Reapply r269100 and r269270, reverted due to
https://llvm.org/bugs/show_bug.cgi?id=27725. Isolate the testcase that
corresponds to the new feature side of this commit and skip it on
windows hosts until we find why it does not work on these platforms.
Original commit message:
The way we currently build the internal VFS overlay representation leads
to inefficient path search and might yield wrong answers when asked for
recursive or regular directory iteration.
Currently, when reading an YAML file, each YAML root entry is placed
inside a new root in the filesystem overlay. In the crash reproducer, a
simple "@import Foundation" currently maps to 43 roots, and when looking
up paths, we traverse a directory tree for each of these different
roots, until we find a match (or don't). This has two consequences:
- It's slow.
- Directory iteration gives incomplete results since it only return
results within one root - since contents of the same directory can be
declared inside different roots, the result isn't accurate.
This is in part fault of the way we currently write out the YAML file
when emitting the crash reproducer - we could generate only one root and
that would make it fast and correct again. However, we should not rely
on how the client writes the YAML, but provide a good internal
representation regardless.
Build a proper virtual directory tree out of the YAML representation,
allowing faster search and proper iteration. Besides the crash
reproducer, this potentially benefits other VFS clients.
llvm-svn: 269327
2016-05-12 19:13:07 +00:00
|
|
|
llvm::make_range(DE->contents_begin(), DE->contents_end())) {
|
2019-01-15 22:36:41 +00:00
|
|
|
auto *DirContent =
|
2021-01-16 11:44:14 +10:00
|
|
|
dyn_cast<RedirectingFileSystem::DirectoryEntry>(Content.get());
|
2024-05-08 10:33:53 -07:00
|
|
|
if (DirContent && Name == Content->getName())
|
[VFS] Reapply #2: Reconstruct the VFS overlay tree for more accurate lookup
Reapply r269100 and r269270, reverted due to
https://llvm.org/bugs/show_bug.cgi?id=27725. Isolate the testcase that
corresponds to the new feature side of this commit and skip it on
windows hosts until we find why it does not work on these platforms.
Original commit message:
The way we currently build the internal VFS overlay representation leads
to inefficient path search and might yield wrong answers when asked for
recursive or regular directory iteration.
Currently, when reading an YAML file, each YAML root entry is placed
inside a new root in the filesystem overlay. In the crash reproducer, a
simple "@import Foundation" currently maps to 43 roots, and when looking
up paths, we traverse a directory tree for each of these different
roots, until we find a match (or don't). This has two consequences:
- It's slow.
- Directory iteration gives incomplete results since it only return
results within one root - since contents of the same directory can be
declared inside different roots, the result isn't accurate.
This is in part fault of the way we currently write out the YAML file
when emitting the crash reproducer - we could generate only one root and
that would make it fast and correct again. However, we should not rely
on how the client writes the YAML, but provide a good internal
representation regardless.
Build a proper virtual directory tree out of the YAML representation,
allowing faster search and proper iteration. Besides the crash
reproducer, this potentially benefits other VFS clients.
llvm-svn: 269327
2016-05-12 19:13:07 +00:00
|
|
|
return DirContent;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ... or create a new one
|
2019-01-15 22:36:41 +00:00
|
|
|
std::unique_ptr<RedirectingFileSystem::Entry> E =
|
2021-01-16 11:44:14 +10:00
|
|
|
std::make_unique<RedirectingFileSystem::DirectoryEntry>(
|
2019-01-15 22:36:41 +00:00
|
|
|
Name, Status("", getNextVirtualUniqueID(),
|
|
|
|
std::chrono::system_clock::now(), 0, 0, 0,
|
|
|
|
file_type::directory_file, sys::fs::all_all));
|
[VFS] Reapply #2: Reconstruct the VFS overlay tree for more accurate lookup
Reapply r269100 and r269270, reverted due to
https://llvm.org/bugs/show_bug.cgi?id=27725. Isolate the testcase that
corresponds to the new feature side of this commit and skip it on
windows hosts until we find why it does not work on these platforms.
Original commit message:
The way we currently build the internal VFS overlay representation leads
to inefficient path search and might yield wrong answers when asked for
recursive or regular directory iteration.
Currently, when reading an YAML file, each YAML root entry is placed
inside a new root in the filesystem overlay. In the crash reproducer, a
simple "@import Foundation" currently maps to 43 roots, and when looking
up paths, we traverse a directory tree for each of these different
roots, until we find a match (or don't). This has two consequences:
- It's slow.
- Directory iteration gives incomplete results since it only return
results within one root - since contents of the same directory can be
declared inside different roots, the result isn't accurate.
This is in part fault of the way we currently write out the YAML file
when emitting the crash reproducer - we could generate only one root and
that would make it fast and correct again. However, we should not rely
on how the client writes the YAML, but provide a good internal
representation regardless.
Build a proper virtual directory tree out of the YAML representation,
allowing faster search and proper iteration. Besides the crash
reproducer, this potentially benefits other VFS clients.
llvm-svn: 269327
2016-05-12 19:13:07 +00:00
|
|
|
|
|
|
|
if (!ParentEntry) { // Add a new root to the overlay
|
|
|
|
FS->Roots.push_back(std::move(E));
|
|
|
|
ParentEntry = FS->Roots.back().get();
|
|
|
|
return ParentEntry;
|
|
|
|
}
|
|
|
|
|
2021-01-16 11:44:14 +10:00
|
|
|
auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(ParentEntry);
|
[VFS] Reapply #2: Reconstruct the VFS overlay tree for more accurate lookup
Reapply r269100 and r269270, reverted due to
https://llvm.org/bugs/show_bug.cgi?id=27725. Isolate the testcase that
corresponds to the new feature side of this commit and skip it on
windows hosts until we find why it does not work on these platforms.
Original commit message:
The way we currently build the internal VFS overlay representation leads
to inefficient path search and might yield wrong answers when asked for
recursive or regular directory iteration.
Currently, when reading an YAML file, each YAML root entry is placed
inside a new root in the filesystem overlay. In the crash reproducer, a
simple "@import Foundation" currently maps to 43 roots, and when looking
up paths, we traverse a directory tree for each of these different
roots, until we find a match (or don't). This has two consequences:
- It's slow.
- Directory iteration gives incomplete results since it only return
results within one root - since contents of the same directory can be
declared inside different roots, the result isn't accurate.
This is in part fault of the way we currently write out the YAML file
when emitting the crash reproducer - we could generate only one root and
that would make it fast and correct again. However, we should not rely
on how the client writes the YAML, but provide a good internal
representation regardless.
Build a proper virtual directory tree out of the YAML representation,
allowing faster search and proper iteration. Besides the crash
reproducer, this potentially benefits other VFS clients.
llvm-svn: 269327
2016-05-12 19:13:07 +00:00
|
|
|
DE->addContent(std::move(E));
|
|
|
|
return DE->getLastContent();
|
|
|
|
}
|
|
|
|
|
2020-11-11 23:03:38 -05:00
|
|
|
private:
|
2019-01-15 22:36:41 +00:00
|
|
|
void uniqueOverlayTree(RedirectingFileSystem *FS,
|
|
|
|
RedirectingFileSystem::Entry *SrcE,
|
|
|
|
RedirectingFileSystem::Entry *NewParentE = nullptr) {
|
[VFS] Reapply #2: Reconstruct the VFS overlay tree for more accurate lookup
Reapply r269100 and r269270, reverted due to
https://llvm.org/bugs/show_bug.cgi?id=27725. Isolate the testcase that
corresponds to the new feature side of this commit and skip it on
windows hosts until we find why it does not work on these platforms.
Original commit message:
The way we currently build the internal VFS overlay representation leads
to inefficient path search and might yield wrong answers when asked for
recursive or regular directory iteration.
Currently, when reading an YAML file, each YAML root entry is placed
inside a new root in the filesystem overlay. In the crash reproducer, a
simple "@import Foundation" currently maps to 43 roots, and when looking
up paths, we traverse a directory tree for each of these different
roots, until we find a match (or don't). This has two consequences:
- It's slow.
- Directory iteration gives incomplete results since it only return
results within one root - since contents of the same directory can be
declared inside different roots, the result isn't accurate.
This is in part fault of the way we currently write out the YAML file
when emitting the crash reproducer - we could generate only one root and
that would make it fast and correct again. However, we should not rely
on how the client writes the YAML, but provide a good internal
representation regardless.
Build a proper virtual directory tree out of the YAML representation,
allowing faster search and proper iteration. Besides the crash
reproducer, this potentially benefits other VFS clients.
llvm-svn: 269327
2016-05-12 19:13:07 +00:00
|
|
|
StringRef Name = SrcE->getName();
|
|
|
|
switch (SrcE->getKind()) {
|
2019-01-15 22:36:41 +00:00
|
|
|
case RedirectingFileSystem::EK_Directory: {
|
2021-01-16 11:44:14 +10:00
|
|
|
auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(SrcE);
|
[VFS] Reapply #2: Reconstruct the VFS overlay tree for more accurate lookup
Reapply r269100 and r269270, reverted due to
https://llvm.org/bugs/show_bug.cgi?id=27725. Isolate the testcase that
corresponds to the new feature side of this commit and skip it on
windows hosts until we find why it does not work on these platforms.
Original commit message:
The way we currently build the internal VFS overlay representation leads
to inefficient path search and might yield wrong answers when asked for
recursive or regular directory iteration.
Currently, when reading an YAML file, each YAML root entry is placed
inside a new root in the filesystem overlay. In the crash reproducer, a
simple "@import Foundation" currently maps to 43 roots, and when looking
up paths, we traverse a directory tree for each of these different
roots, until we find a match (or don't). This has two consequences:
- It's slow.
- Directory iteration gives incomplete results since it only return
results within one root - since contents of the same directory can be
declared inside different roots, the result isn't accurate.
This is in part fault of the way we currently write out the YAML file
when emitting the crash reproducer - we could generate only one root and
that would make it fast and correct again. However, we should not rely
on how the client writes the YAML, but provide a good internal
representation regardless.
Build a proper virtual directory tree out of the YAML representation,
allowing faster search and proper iteration. Besides the crash
reproducer, this potentially benefits other VFS clients.
llvm-svn: 269327
2016-05-12 19:13:07 +00:00
|
|
|
// Empty directories could be present in the YAML as a way to
|
|
|
|
// describe a file for a current directory after some of its subdir
|
|
|
|
// is parsed. This only leads to redundant walks, ignore it.
|
|
|
|
if (!Name.empty())
|
|
|
|
NewParentE = lookupOrCreateEntry(FS, Name, NewParentE);
|
2019-01-15 22:36:41 +00:00
|
|
|
for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
|
[VFS] Reapply #2: Reconstruct the VFS overlay tree for more accurate lookup
Reapply r269100 and r269270, reverted due to
https://llvm.org/bugs/show_bug.cgi?id=27725. Isolate the testcase that
corresponds to the new feature side of this commit and skip it on
windows hosts until we find why it does not work on these platforms.
Original commit message:
The way we currently build the internal VFS overlay representation leads
to inefficient path search and might yield wrong answers when asked for
recursive or regular directory iteration.
Currently, when reading an YAML file, each YAML root entry is placed
inside a new root in the filesystem overlay. In the crash reproducer, a
simple "@import Foundation" currently maps to 43 roots, and when looking
up paths, we traverse a directory tree for each of these different
roots, until we find a match (or don't). This has two consequences:
- It's slow.
- Directory iteration gives incomplete results since it only return
results within one root - since contents of the same directory can be
declared inside different roots, the result isn't accurate.
This is in part fault of the way we currently write out the YAML file
when emitting the crash reproducer - we could generate only one root and
that would make it fast and correct again. However, we should not rely
on how the client writes the YAML, but provide a good internal
representation regardless.
Build a proper virtual directory tree out of the YAML representation,
allowing faster search and proper iteration. Besides the crash
reproducer, this potentially benefits other VFS clients.
llvm-svn: 269327
2016-05-12 19:13:07 +00:00
|
|
|
llvm::make_range(DE->contents_begin(), DE->contents_end()))
|
|
|
|
uniqueOverlayTree(FS, SubEntry.get(), NewParentE);
|
|
|
|
break;
|
|
|
|
}
|
2021-01-15 17:33:52 +10:00
|
|
|
case RedirectingFileSystem::EK_DirectoryRemap: {
|
|
|
|
assert(NewParentE && "Parent entry must exist");
|
|
|
|
auto *DR = cast<RedirectingFileSystem::DirectoryRemapEntry>(SrcE);
|
|
|
|
auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(NewParentE);
|
|
|
|
DE->addContent(
|
|
|
|
std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
|
|
|
|
Name, DR->getExternalContentsPath(), DR->getUseName()));
|
|
|
|
break;
|
|
|
|
}
|
2019-01-15 22:36:41 +00:00
|
|
|
case RedirectingFileSystem::EK_File: {
|
[VFS] Reapply #2: Reconstruct the VFS overlay tree for more accurate lookup
Reapply r269100 and r269270, reverted due to
https://llvm.org/bugs/show_bug.cgi?id=27725. Isolate the testcase that
corresponds to the new feature side of this commit and skip it on
windows hosts until we find why it does not work on these platforms.
Original commit message:
The way we currently build the internal VFS overlay representation leads
to inefficient path search and might yield wrong answers when asked for
recursive or regular directory iteration.
Currently, when reading an YAML file, each YAML root entry is placed
inside a new root in the filesystem overlay. In the crash reproducer, a
simple "@import Foundation" currently maps to 43 roots, and when looking
up paths, we traverse a directory tree for each of these different
roots, until we find a match (or don't). This has two consequences:
- It's slow.
- Directory iteration gives incomplete results since it only return
results within one root - since contents of the same directory can be
declared inside different roots, the result isn't accurate.
This is in part fault of the way we currently write out the YAML file
when emitting the crash reproducer - we could generate only one root and
that would make it fast and correct again. However, we should not rely
on how the client writes the YAML, but provide a good internal
representation regardless.
Build a proper virtual directory tree out of the YAML representation,
allowing faster search and proper iteration. Besides the crash
reproducer, this potentially benefits other VFS clients.
llvm-svn: 269327
2016-05-12 19:13:07 +00:00
|
|
|
assert(NewParentE && "Parent entry must exist");
|
2021-01-16 11:44:14 +10:00
|
|
|
auto *FE = cast<RedirectingFileSystem::FileEntry>(SrcE);
|
|
|
|
auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(NewParentE);
|
|
|
|
DE->addContent(std::make_unique<RedirectingFileSystem::FileEntry>(
|
|
|
|
Name, FE->getExternalContentsPath(), FE->getUseName()));
|
[VFS] Reapply #2: Reconstruct the VFS overlay tree for more accurate lookup
Reapply r269100 and r269270, reverted due to
https://llvm.org/bugs/show_bug.cgi?id=27725. Isolate the testcase that
corresponds to the new feature side of this commit and skip it on
windows hosts until we find why it does not work on these platforms.
Original commit message:
The way we currently build the internal VFS overlay representation leads
to inefficient path search and might yield wrong answers when asked for
recursive or regular directory iteration.
Currently, when reading an YAML file, each YAML root entry is placed
inside a new root in the filesystem overlay. In the crash reproducer, a
simple "@import Foundation" currently maps to 43 roots, and when looking
up paths, we traverse a directory tree for each of these different
roots, until we find a match (or don't). This has two consequences:
- It's slow.
- Directory iteration gives incomplete results since it only return
results within one root - since contents of the same directory can be
declared inside different roots, the result isn't accurate.
This is in part fault of the way we currently write out the YAML file
when emitting the crash reproducer - we could generate only one root and
that would make it fast and correct again. However, we should not rely
on how the client writes the YAML, but provide a good internal
representation regardless.
Build a proper virtual directory tree out of the YAML representation,
allowing faster search and proper iteration. Besides the crash
reproducer, this potentially benefits other VFS clients.
llvm-svn: 269327
2016-05-12 19:13:07 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-15 22:36:41 +00:00
|
|
|
std::unique_ptr<RedirectingFileSystem::Entry>
|
|
|
|
parseEntry(yaml::Node *N, RedirectingFileSystem *FS, bool IsRootEntry) {
|
2018-03-28 22:09:09 +00:00
|
|
|
auto *M = dyn_cast<yaml::MappingNode>(N);
|
2014-02-21 23:39:37 +00:00
|
|
|
if (!M) {
|
|
|
|
error(N, "expected mapping node for file or directory entry");
|
2014-05-08 06:41:40 +00:00
|
|
|
return nullptr;
|
2014-02-21 23:39:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
KeyStatusPair Fields[] = {
|
2018-10-10 13:27:25 +00:00
|
|
|
KeyStatusPair("name", true),
|
|
|
|
KeyStatusPair("type", true),
|
|
|
|
KeyStatusPair("contents", false),
|
|
|
|
KeyStatusPair("external-contents", false),
|
|
|
|
KeyStatusPair("use-external-name", false),
|
2014-02-21 23:39:37 +00:00
|
|
|
};
|
|
|
|
|
2015-11-30 03:11:10 +00:00
|
|
|
DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields));
|
2014-02-21 23:39:37 +00:00
|
|
|
|
2021-01-15 17:33:52 +10:00
|
|
|
enum { CF_NotSet, CF_List, CF_External } ContentsField = CF_NotSet;
|
2019-01-15 22:36:41 +00:00
|
|
|
std::vector<std::unique_ptr<RedirectingFileSystem::Entry>>
|
|
|
|
EntryArrayContents;
|
2020-01-21 16:45:51 -08:00
|
|
|
SmallString<256> ExternalContentsPath;
|
|
|
|
SmallString<256> Name;
|
2019-05-22 11:20:52 +00:00
|
|
|
yaml::Node *NameValueNode = nullptr;
|
2021-01-15 17:33:52 +10:00
|
|
|
auto UseExternalName = RedirectingFileSystem::NK_NotSet;
|
2019-01-15 22:36:41 +00:00
|
|
|
RedirectingFileSystem::EntryKind Kind;
|
2014-02-21 23:39:37 +00:00
|
|
|
|
2018-03-28 22:09:09 +00:00
|
|
|
for (auto &I : *M) {
|
2014-02-21 23:39:37 +00:00
|
|
|
StringRef Key;
|
|
|
|
// Reuse the buffer for key and value, since we don't look at key after
|
|
|
|
// parsing value.
|
|
|
|
SmallString<256> Buffer;
|
2018-03-28 22:09:09 +00:00
|
|
|
if (!parseScalarString(I.getKey(), Key, Buffer))
|
2014-05-08 06:41:40 +00:00
|
|
|
return nullptr;
|
2014-02-21 23:39:37 +00:00
|
|
|
|
2018-03-28 22:09:09 +00:00
|
|
|
if (!checkDuplicateOrUnknownKey(I.getKey(), Key, Keys))
|
2014-05-08 06:41:40 +00:00
|
|
|
return nullptr;
|
2014-02-21 23:39:37 +00:00
|
|
|
|
|
|
|
StringRef Value;
|
|
|
|
if (Key == "name") {
|
2018-03-28 22:09:09 +00:00
|
|
|
if (!parseScalarString(I.getValue(), Value, Buffer))
|
2014-05-08 06:41:40 +00:00
|
|
|
return nullptr;
|
2016-03-17 02:20:43 +00:00
|
|
|
|
2018-08-07 19:05:41 +00:00
|
|
|
NameValueNode = I.getValue();
|
2020-01-21 16:45:51 -08:00
|
|
|
// Guarantee that old YAML files containing paths with ".." and "."
|
|
|
|
// are properly canonicalized before read into the VFS.
|
|
|
|
Name = canonicalize(Value).str();
|
2014-02-21 23:39:37 +00:00
|
|
|
} else if (Key == "type") {
|
2018-03-28 22:09:09 +00:00
|
|
|
if (!parseScalarString(I.getValue(), Value, Buffer))
|
2014-05-08 06:41:40 +00:00
|
|
|
return nullptr;
|
2014-02-21 23:39:37 +00:00
|
|
|
if (Value == "file")
|
2019-01-15 22:36:41 +00:00
|
|
|
Kind = RedirectingFileSystem::EK_File;
|
2014-02-21 23:39:37 +00:00
|
|
|
else if (Value == "directory")
|
2019-01-15 22:36:41 +00:00
|
|
|
Kind = RedirectingFileSystem::EK_Directory;
|
2021-01-15 17:33:52 +10:00
|
|
|
else if (Value == "directory-remap")
|
|
|
|
Kind = RedirectingFileSystem::EK_DirectoryRemap;
|
2014-02-21 23:39:37 +00:00
|
|
|
else {
|
2018-03-28 22:09:09 +00:00
|
|
|
error(I.getValue(), "unknown value for 'type'");
|
2014-05-08 06:41:40 +00:00
|
|
|
return nullptr;
|
2014-02-21 23:39:37 +00:00
|
|
|
}
|
|
|
|
} else if (Key == "contents") {
|
2021-01-15 17:33:52 +10:00
|
|
|
if (ContentsField != CF_NotSet) {
|
2018-03-28 22:09:09 +00:00
|
|
|
error(I.getKey(),
|
2014-02-21 23:39:37 +00:00
|
|
|
"entry already has 'contents' or 'external-contents'");
|
2014-05-08 06:41:40 +00:00
|
|
|
return nullptr;
|
2014-02-21 23:39:37 +00:00
|
|
|
}
|
2021-01-15 17:33:52 +10:00
|
|
|
ContentsField = CF_List;
|
2018-03-28 22:09:09 +00:00
|
|
|
auto *Contents = dyn_cast<yaml::SequenceNode>(I.getValue());
|
2014-02-21 23:39:37 +00:00
|
|
|
if (!Contents) {
|
|
|
|
// FIXME: this is only for directories, what about files?
|
2018-03-28 22:09:09 +00:00
|
|
|
error(I.getValue(), "expected array");
|
2014-05-08 06:41:40 +00:00
|
|
|
return nullptr;
|
2014-02-21 23:39:37 +00:00
|
|
|
}
|
|
|
|
|
2018-03-28 22:09:09 +00:00
|
|
|
for (auto &I : *Contents) {
|
2019-01-15 22:36:41 +00:00
|
|
|
if (std::unique_ptr<RedirectingFileSystem::Entry> E =
|
2018-08-07 19:05:41 +00:00
|
|
|
parseEntry(&I, FS, /*IsRootEntry*/ false))
|
2015-10-07 10:05:44 +00:00
|
|
|
EntryArrayContents.push_back(std::move(E));
|
2014-02-21 23:39:37 +00:00
|
|
|
else
|
2014-05-08 06:41:40 +00:00
|
|
|
return nullptr;
|
2014-02-21 23:39:37 +00:00
|
|
|
}
|
|
|
|
} else if (Key == "external-contents") {
|
2021-01-15 17:33:52 +10:00
|
|
|
if (ContentsField != CF_NotSet) {
|
2018-03-28 22:09:09 +00:00
|
|
|
error(I.getKey(),
|
2014-02-21 23:39:37 +00:00
|
|
|
"entry already has 'contents' or 'external-contents'");
|
2014-05-08 06:41:40 +00:00
|
|
|
return nullptr;
|
2014-02-21 23:39:37 +00:00
|
|
|
}
|
2021-01-15 17:33:52 +10:00
|
|
|
ContentsField = CF_External;
|
2018-03-28 22:09:09 +00:00
|
|
|
if (!parseScalarString(I.getValue(), Value, Buffer))
|
2014-05-08 06:41:40 +00:00
|
|
|
return nullptr;
|
Reapply [2] [VFS] Add 'overlay-relative' field to YAML files
This reapplies r261552 and r263748. Fixed testcase to reapply.
The VFS overlay mapping between virtual paths and real paths is done through
the 'external-contents' entries in YAML files, which contains hardcoded paths
to the real files.
When a module compilation crashes, headers are dumped into <name>.cache/vfs
directory and are mapped via the <name>.cache/vfs/vfs.yaml. The script
generated for reproduction uses -ivfsoverlay pointing to file to gather the
mapping between virtual paths and files inside <name>.cache/vfs. Currently, we
are only capable of reproducing such crashes in the same machine as they
happen, because of the hardcoded paths in 'external-contents'.
To be able to reproduce a crash in another machine, this patch introduces a new
option in the VFS yaml file called 'overlay-relative'. When it's equal to
'true' it means that the provided path to the YAML file through the
-ivfsoverlay option should also be used to prefix the final path for every
'external-contents'.
Example, given the invocation snippet "... -ivfsoverlay
<name>.cache/vfs/vfs.yaml" and the following entry in the yaml file:
"overlay-relative": "true",
"roots": [
...
"type": "directory",
"name": "/usr/include",
"contents": [
{
"type": "file",
"name": "stdio.h",
"external-contents": "/usr/include/stdio.h"
},
...
Here, a file manager request for virtual "/usr/include/stdio.h", that will map
into real path "/<absolute_path_to>/<name>.cache/vfs/usr/include/stdio.h.
This is a useful feature for debugging module crashes in machines other than
the one where the error happened.
Differential Revision: http://reviews.llvm.org/D17457
rdar://problem/24499339
llvm-svn: 263893
2016-03-20 02:08:48 +00:00
|
|
|
|
|
|
|
SmallString<256> FullPath;
|
|
|
|
if (FS->IsRelativeOverlay) {
|
2022-11-04 16:40:10 -07:00
|
|
|
FullPath = FS->getOverlayFileDir();
|
Reapply [2] [VFS] Add 'overlay-relative' field to YAML files
This reapplies r261552 and r263748. Fixed testcase to reapply.
The VFS overlay mapping between virtual paths and real paths is done through
the 'external-contents' entries in YAML files, which contains hardcoded paths
to the real files.
When a module compilation crashes, headers are dumped into <name>.cache/vfs
directory and are mapped via the <name>.cache/vfs/vfs.yaml. The script
generated for reproduction uses -ivfsoverlay pointing to file to gather the
mapping between virtual paths and files inside <name>.cache/vfs. Currently, we
are only capable of reproducing such crashes in the same machine as they
happen, because of the hardcoded paths in 'external-contents'.
To be able to reproduce a crash in another machine, this patch introduces a new
option in the VFS yaml file called 'overlay-relative'. When it's equal to
'true' it means that the provided path to the YAML file through the
-ivfsoverlay option should also be used to prefix the final path for every
'external-contents'.
Example, given the invocation snippet "... -ivfsoverlay
<name>.cache/vfs/vfs.yaml" and the following entry in the yaml file:
"overlay-relative": "true",
"roots": [
...
"type": "directory",
"name": "/usr/include",
"contents": [
{
"type": "file",
"name": "stdio.h",
"external-contents": "/usr/include/stdio.h"
},
...
Here, a file manager request for virtual "/usr/include/stdio.h", that will map
into real path "/<absolute_path_to>/<name>.cache/vfs/usr/include/stdio.h.
This is a useful feature for debugging module crashes in machines other than
the one where the error happened.
Differential Revision: http://reviews.llvm.org/D17457
rdar://problem/24499339
llvm-svn: 263893
2016-03-20 02:08:48 +00:00
|
|
|
assert(!FullPath.empty() &&
|
|
|
|
"External contents prefix directory must exist");
|
|
|
|
llvm::sys::path::append(FullPath, Value);
|
|
|
|
} else {
|
|
|
|
FullPath = Value;
|
|
|
|
}
|
|
|
|
|
2020-01-21 16:45:51 -08:00
|
|
|
// Guarantee that old YAML files containing paths with ".." and "."
|
|
|
|
// are properly canonicalized before read into the VFS.
|
|
|
|
FullPath = canonicalize(FullPath);
|
|
|
|
ExternalContentsPath = FullPath.str();
|
2014-02-27 00:25:12 +00:00
|
|
|
} else if (Key == "use-external-name") {
|
|
|
|
bool Val;
|
2018-03-28 22:09:09 +00:00
|
|
|
if (!parseScalarBool(I.getValue(), Val))
|
2014-05-08 06:41:40 +00:00
|
|
|
return nullptr;
|
2021-01-15 17:33:52 +10:00
|
|
|
UseExternalName = Val ? RedirectingFileSystem::NK_External
|
|
|
|
: RedirectingFileSystem::NK_Virtual;
|
2014-02-21 23:39:37 +00:00
|
|
|
} else {
|
|
|
|
llvm_unreachable("key missing from Keys");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Stream.failed())
|
2014-05-08 06:41:40 +00:00
|
|
|
return nullptr;
|
2014-02-21 23:39:37 +00:00
|
|
|
|
|
|
|
// check for missing keys
|
2021-01-15 17:33:52 +10:00
|
|
|
if (ContentsField == CF_NotSet) {
|
2014-02-21 23:39:37 +00:00
|
|
|
error(N, "missing key 'contents' or 'external-contents'");
|
2014-05-08 06:41:40 +00:00
|
|
|
return nullptr;
|
2014-02-21 23:39:37 +00:00
|
|
|
}
|
|
|
|
if (!checkMissingKeys(N, Keys))
|
2014-05-08 06:41:40 +00:00
|
|
|
return nullptr;
|
2014-02-21 23:39:37 +00:00
|
|
|
|
2014-02-27 00:25:12 +00:00
|
|
|
// check invalid configuration
|
2019-01-15 22:36:41 +00:00
|
|
|
if (Kind == RedirectingFileSystem::EK_Directory &&
|
2021-01-15 17:33:52 +10:00
|
|
|
UseExternalName != RedirectingFileSystem::NK_NotSet) {
|
|
|
|
error(N, "'use-external-name' is not supported for 'directory' entries");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Kind == RedirectingFileSystem::EK_DirectoryRemap &&
|
|
|
|
ContentsField == CF_List) {
|
|
|
|
error(N, "'contents' is not supported for 'directory-remap' entries");
|
2014-05-08 06:41:40 +00:00
|
|
|
return nullptr;
|
2014-02-27 00:25:12 +00:00
|
|
|
}
|
|
|
|
|
2019-11-25 15:57:21 -08:00
|
|
|
sys::path::Style path_style = sys::path::Style::native;
|
|
|
|
if (IsRootEntry) {
|
|
|
|
// VFS root entries may be in either Posix or Windows style. Figure out
|
|
|
|
// which style we have, and use it consistently.
|
|
|
|
if (sys::path::is_absolute(Name, sys::path::Style::posix)) {
|
|
|
|
path_style = sys::path::Style::posix;
|
2021-10-08 10:41:46 +00:00
|
|
|
} else if (sys::path::is_absolute(Name,
|
|
|
|
sys::path::Style::windows_backslash)) {
|
|
|
|
path_style = sys::path::Style::windows_backslash;
|
2019-11-25 15:57:21 -08:00
|
|
|
} else {
|
2022-11-04 16:40:10 -07:00
|
|
|
// Relative VFS root entries are made absolute to either the overlay
|
|
|
|
// directory, or the current working directory, then we can determine
|
|
|
|
// the path style from that.
|
|
|
|
std::error_code EC;
|
|
|
|
if (FS->RootRelative ==
|
|
|
|
RedirectingFileSystem::RootRelativeKind::OverlayDir) {
|
|
|
|
StringRef FullPath = FS->getOverlayFileDir();
|
|
|
|
assert(!FullPath.empty() && "Overlay file directory must exist");
|
|
|
|
EC = FS->makeAbsolute(FullPath, Name);
|
|
|
|
Name = canonicalize(Name);
|
|
|
|
} else {
|
|
|
|
EC = sys::fs::make_absolute(Name);
|
|
|
|
}
|
2022-01-19 10:12:32 -08:00
|
|
|
if (EC) {
|
|
|
|
assert(NameValueNode && "Name presence should be checked earlier");
|
|
|
|
error(
|
|
|
|
NameValueNode,
|
2019-11-25 15:57:21 -08:00
|
|
|
"entry with relative path at the root level is not discoverable");
|
2022-01-19 10:12:32 -08:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
path_style = sys::path::is_absolute(Name, sys::path::Style::posix)
|
|
|
|
? sys::path::Style::posix
|
|
|
|
: sys::path::Style::windows_backslash;
|
2019-11-25 15:57:21 -08:00
|
|
|
}
|
2022-11-04 16:40:10 -07:00
|
|
|
// is::path::is_absolute(Name, sys::path::Style::windows_backslash) will
|
|
|
|
// return true even if `Name` is using forward slashes. Distinguish
|
|
|
|
// between windows_backslash and windows_slash.
|
|
|
|
if (path_style == sys::path::Style::windows_backslash &&
|
|
|
|
getExistingStyle(Name) != sys::path::Style::windows_backslash)
|
|
|
|
path_style = sys::path::Style::windows_slash;
|
2018-08-07 19:05:41 +00:00
|
|
|
}
|
|
|
|
|
2014-03-05 21:32:20 +00:00
|
|
|
// Remove trailing slash(es), being careful not to remove the root path
|
2021-07-08 13:30:14 -07:00
|
|
|
StringRef Trimmed = Name;
|
2019-11-25 15:57:21 -08:00
|
|
|
size_t RootPathLen = sys::path::root_path(Trimmed, path_style).size();
|
2014-03-05 21:32:20 +00:00
|
|
|
while (Trimmed.size() > RootPathLen &&
|
2019-11-25 15:57:21 -08:00
|
|
|
sys::path::is_separator(Trimmed.back(), path_style))
|
2018-10-10 13:27:25 +00:00
|
|
|
Trimmed = Trimmed.slice(0, Trimmed.size() - 1);
|
2019-11-25 15:57:21 -08:00
|
|
|
|
2014-02-25 04:34:14 +00:00
|
|
|
// Get the last component
|
2019-11-25 15:57:21 -08:00
|
|
|
StringRef LastComponent = sys::path::filename(Trimmed, path_style);
|
2014-02-25 04:34:14 +00:00
|
|
|
|
2019-01-15 22:36:41 +00:00
|
|
|
std::unique_ptr<RedirectingFileSystem::Entry> Result;
|
2014-02-21 23:39:37 +00:00
|
|
|
switch (Kind) {
|
2019-01-15 22:36:41 +00:00
|
|
|
case RedirectingFileSystem::EK_File:
|
2021-01-16 11:44:14 +10:00
|
|
|
Result = std::make_unique<RedirectingFileSystem::FileEntry>(
|
2015-10-07 10:05:44 +00:00
|
|
|
LastComponent, std::move(ExternalContentsPath), UseExternalName);
|
2014-02-25 04:34:14 +00:00
|
|
|
break;
|
2021-01-15 17:33:52 +10:00
|
|
|
case RedirectingFileSystem::EK_DirectoryRemap:
|
|
|
|
Result = std::make_unique<RedirectingFileSystem::DirectoryRemapEntry>(
|
|
|
|
LastComponent, std::move(ExternalContentsPath), UseExternalName);
|
|
|
|
break;
|
2019-01-15 22:36:41 +00:00
|
|
|
case RedirectingFileSystem::EK_Directory:
|
2021-01-16 11:44:14 +10:00
|
|
|
Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
|
|
|
|
LastComponent, std::move(EntryArrayContents),
|
|
|
|
Status("", getNextVirtualUniqueID(), std::chrono::system_clock::now(),
|
|
|
|
0, 0, 0, file_type::directory_file, sys::fs::all_all));
|
2014-02-25 04:34:14 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-11-25 15:57:21 -08:00
|
|
|
StringRef Parent = sys::path::parent_path(Trimmed, path_style);
|
2014-02-25 04:34:14 +00:00
|
|
|
if (Parent.empty())
|
|
|
|
return Result;
|
|
|
|
|
|
|
|
// if 'name' contains multiple components, create implicit directory entries
|
2019-11-25 15:57:21 -08:00
|
|
|
for (sys::path::reverse_iterator I = sys::path::rbegin(Parent, path_style),
|
2014-02-25 04:34:14 +00:00
|
|
|
E = sys::path::rend(Parent);
|
|
|
|
I != E; ++I) {
|
2019-01-15 22:36:41 +00:00
|
|
|
std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> Entries;
|
2015-10-07 10:05:44 +00:00
|
|
|
Entries.push_back(std::move(Result));
|
2021-01-16 11:44:14 +10:00
|
|
|
Result = std::make_unique<RedirectingFileSystem::DirectoryEntry>(
|
|
|
|
*I, std::move(Entries),
|
|
|
|
Status("", getNextVirtualUniqueID(), std::chrono::system_clock::now(),
|
|
|
|
0, 0, 0, file_type::directory_file, sys::fs::all_all));
|
2014-02-21 23:39:37 +00:00
|
|
|
}
|
2014-02-25 04:34:14 +00:00
|
|
|
return Result;
|
2014-02-21 23:39:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
2015-10-07 10:05:44 +00:00
|
|
|
RedirectingFileSystemParser(yaml::Stream &S) : Stream(S) {}
|
2014-02-21 23:39:37 +00:00
|
|
|
|
|
|
|
// false on error
|
2015-10-07 10:05:44 +00:00
|
|
|
bool parse(yaml::Node *Root, RedirectingFileSystem *FS) {
|
2018-03-28 22:09:09 +00:00
|
|
|
auto *Top = dyn_cast<yaml::MappingNode>(Root);
|
2014-02-21 23:39:37 +00:00
|
|
|
if (!Top) {
|
|
|
|
error(Root, "expected mapping node");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
KeyStatusPair Fields[] = {
|
2018-10-10 13:27:25 +00:00
|
|
|
KeyStatusPair("version", true),
|
|
|
|
KeyStatusPair("case-sensitive", false),
|
|
|
|
KeyStatusPair("use-external-names", false),
|
2022-11-04 16:40:10 -07:00
|
|
|
KeyStatusPair("root-relative", false),
|
2018-10-10 13:27:25 +00:00
|
|
|
KeyStatusPair("overlay-relative", false),
|
2018-10-26 22:14:33 +00:00
|
|
|
KeyStatusPair("fallthrough", false),
|
2022-02-03 12:53:22 -08:00
|
|
|
KeyStatusPair("redirecting-with", false),
|
2018-10-10 13:27:25 +00:00
|
|
|
KeyStatusPair("roots", true),
|
2014-02-21 23:39:37 +00:00
|
|
|
};
|
|
|
|
|
2015-11-30 03:11:10 +00:00
|
|
|
DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields));
|
2019-01-15 22:36:41 +00:00
|
|
|
std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> RootEntries;
|
2014-02-21 23:39:37 +00:00
|
|
|
|
|
|
|
// Parse configuration and 'roots'
|
2018-03-28 22:09:09 +00:00
|
|
|
for (auto &I : *Top) {
|
2014-02-21 23:39:37 +00:00
|
|
|
SmallString<10> KeyBuffer;
|
|
|
|
StringRef Key;
|
2018-03-28 22:09:09 +00:00
|
|
|
if (!parseScalarString(I.getKey(), Key, KeyBuffer))
|
2014-02-21 23:39:37 +00:00
|
|
|
return false;
|
|
|
|
|
2018-03-28 22:09:09 +00:00
|
|
|
if (!checkDuplicateOrUnknownKey(I.getKey(), Key, Keys))
|
2014-02-21 23:39:37 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (Key == "roots") {
|
2018-03-28 22:09:09 +00:00
|
|
|
auto *Roots = dyn_cast<yaml::SequenceNode>(I.getValue());
|
2014-02-21 23:39:37 +00:00
|
|
|
if (!Roots) {
|
2018-03-28 22:09:09 +00:00
|
|
|
error(I.getValue(), "expected array");
|
2014-02-21 23:39:37 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-03-28 22:09:09 +00:00
|
|
|
for (auto &I : *Roots) {
|
2019-01-15 22:36:41 +00:00
|
|
|
if (std::unique_ptr<RedirectingFileSystem::Entry> E =
|
2018-08-07 19:05:41 +00:00
|
|
|
parseEntry(&I, FS, /*IsRootEntry*/ true))
|
[VFS] Reapply #2: Reconstruct the VFS overlay tree for more accurate lookup
Reapply r269100 and r269270, reverted due to
https://llvm.org/bugs/show_bug.cgi?id=27725. Isolate the testcase that
corresponds to the new feature side of this commit and skip it on
windows hosts until we find why it does not work on these platforms.
Original commit message:
The way we currently build the internal VFS overlay representation leads
to inefficient path search and might yield wrong answers when asked for
recursive or regular directory iteration.
Currently, when reading an YAML file, each YAML root entry is placed
inside a new root in the filesystem overlay. In the crash reproducer, a
simple "@import Foundation" currently maps to 43 roots, and when looking
up paths, we traverse a directory tree for each of these different
roots, until we find a match (or don't). This has two consequences:
- It's slow.
- Directory iteration gives incomplete results since it only return
results within one root - since contents of the same directory can be
declared inside different roots, the result isn't accurate.
This is in part fault of the way we currently write out the YAML file
when emitting the crash reproducer - we could generate only one root and
that would make it fast and correct again. However, we should not rely
on how the client writes the YAML, but provide a good internal
representation regardless.
Build a proper virtual directory tree out of the YAML representation,
allowing faster search and proper iteration. Besides the crash
reproducer, this potentially benefits other VFS clients.
llvm-svn: 269327
2016-05-12 19:13:07 +00:00
|
|
|
RootEntries.push_back(std::move(E));
|
2014-02-21 23:39:37 +00:00
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else if (Key == "version") {
|
|
|
|
StringRef VersionString;
|
|
|
|
SmallString<4> Storage;
|
2018-03-28 22:09:09 +00:00
|
|
|
if (!parseScalarString(I.getValue(), VersionString, Storage))
|
2014-02-21 23:39:37 +00:00
|
|
|
return false;
|
|
|
|
int Version;
|
|
|
|
if (VersionString.getAsInteger<int>(10, Version)) {
|
2018-03-28 22:09:09 +00:00
|
|
|
error(I.getValue(), "expected integer");
|
2014-02-21 23:39:37 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (Version < 0) {
|
2018-03-28 22:09:09 +00:00
|
|
|
error(I.getValue(), "invalid version number");
|
2014-02-21 23:39:37 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (Version != 0) {
|
2018-03-28 22:09:09 +00:00
|
|
|
error(I.getValue(), "version mismatch, expected 0");
|
2014-02-21 23:39:37 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else if (Key == "case-sensitive") {
|
2018-03-28 22:09:09 +00:00
|
|
|
if (!parseScalarBool(I.getValue(), FS->CaseSensitive))
|
2014-02-21 23:39:37 +00:00
|
|
|
return false;
|
Reapply [2] [VFS] Add 'overlay-relative' field to YAML files
This reapplies r261552 and r263748. Fixed testcase to reapply.
The VFS overlay mapping between virtual paths and real paths is done through
the 'external-contents' entries in YAML files, which contains hardcoded paths
to the real files.
When a module compilation crashes, headers are dumped into <name>.cache/vfs
directory and are mapped via the <name>.cache/vfs/vfs.yaml. The script
generated for reproduction uses -ivfsoverlay pointing to file to gather the
mapping between virtual paths and files inside <name>.cache/vfs. Currently, we
are only capable of reproducing such crashes in the same machine as they
happen, because of the hardcoded paths in 'external-contents'.
To be able to reproduce a crash in another machine, this patch introduces a new
option in the VFS yaml file called 'overlay-relative'. When it's equal to
'true' it means that the provided path to the YAML file through the
-ivfsoverlay option should also be used to prefix the final path for every
'external-contents'.
Example, given the invocation snippet "... -ivfsoverlay
<name>.cache/vfs/vfs.yaml" and the following entry in the yaml file:
"overlay-relative": "true",
"roots": [
...
"type": "directory",
"name": "/usr/include",
"contents": [
{
"type": "file",
"name": "stdio.h",
"external-contents": "/usr/include/stdio.h"
},
...
Here, a file manager request for virtual "/usr/include/stdio.h", that will map
into real path "/<absolute_path_to>/<name>.cache/vfs/usr/include/stdio.h.
This is a useful feature for debugging module crashes in machines other than
the one where the error happened.
Differential Revision: http://reviews.llvm.org/D17457
rdar://problem/24499339
llvm-svn: 263893
2016-03-20 02:08:48 +00:00
|
|
|
} else if (Key == "overlay-relative") {
|
2018-03-28 22:09:09 +00:00
|
|
|
if (!parseScalarBool(I.getValue(), FS->IsRelativeOverlay))
|
Reapply [2] [VFS] Add 'overlay-relative' field to YAML files
This reapplies r261552 and r263748. Fixed testcase to reapply.
The VFS overlay mapping between virtual paths and real paths is done through
the 'external-contents' entries in YAML files, which contains hardcoded paths
to the real files.
When a module compilation crashes, headers are dumped into <name>.cache/vfs
directory and are mapped via the <name>.cache/vfs/vfs.yaml. The script
generated for reproduction uses -ivfsoverlay pointing to file to gather the
mapping between virtual paths and files inside <name>.cache/vfs. Currently, we
are only capable of reproducing such crashes in the same machine as they
happen, because of the hardcoded paths in 'external-contents'.
To be able to reproduce a crash in another machine, this patch introduces a new
option in the VFS yaml file called 'overlay-relative'. When it's equal to
'true' it means that the provided path to the YAML file through the
-ivfsoverlay option should also be used to prefix the final path for every
'external-contents'.
Example, given the invocation snippet "... -ivfsoverlay
<name>.cache/vfs/vfs.yaml" and the following entry in the yaml file:
"overlay-relative": "true",
"roots": [
...
"type": "directory",
"name": "/usr/include",
"contents": [
{
"type": "file",
"name": "stdio.h",
"external-contents": "/usr/include/stdio.h"
},
...
Here, a file manager request for virtual "/usr/include/stdio.h", that will map
into real path "/<absolute_path_to>/<name>.cache/vfs/usr/include/stdio.h.
This is a useful feature for debugging module crashes in machines other than
the one where the error happened.
Differential Revision: http://reviews.llvm.org/D17457
rdar://problem/24499339
llvm-svn: 263893
2016-03-20 02:08:48 +00:00
|
|
|
return false;
|
2014-02-27 00:25:12 +00:00
|
|
|
} else if (Key == "use-external-names") {
|
2018-03-28 22:09:09 +00:00
|
|
|
if (!parseScalarBool(I.getValue(), FS->UseExternalNames))
|
2014-02-27 00:25:12 +00:00
|
|
|
return false;
|
2018-10-26 22:14:33 +00:00
|
|
|
} else if (Key == "fallthrough") {
|
2022-02-03 12:53:22 -08:00
|
|
|
if (Keys["redirecting-with"].Seen) {
|
|
|
|
error(I.getValue(),
|
|
|
|
"'fallthrough' and 'redirecting-with' are mutually exclusive");
|
2018-10-26 22:14:33 +00:00
|
|
|
return false;
|
2022-02-03 12:53:22 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ShouldFallthrough = false;
|
|
|
|
if (!parseScalarBool(I.getValue(), ShouldFallthrough))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (ShouldFallthrough) {
|
|
|
|
FS->Redirection = RedirectingFileSystem::RedirectKind::Fallthrough;
|
|
|
|
} else {
|
|
|
|
FS->Redirection = RedirectingFileSystem::RedirectKind::RedirectOnly;
|
|
|
|
}
|
|
|
|
} else if (Key == "redirecting-with") {
|
|
|
|
if (Keys["fallthrough"].Seen) {
|
|
|
|
error(I.getValue(),
|
|
|
|
"'fallthrough' and 'redirecting-with' are mutually exclusive");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (auto Kind = parseRedirectKind(I.getValue())) {
|
|
|
|
FS->Redirection = *Kind;
|
|
|
|
} else {
|
|
|
|
error(I.getValue(), "expected valid redirect kind");
|
|
|
|
return false;
|
|
|
|
}
|
2022-11-04 16:40:10 -07:00
|
|
|
} else if (Key == "root-relative") {
|
|
|
|
if (auto Kind = parseRootRelativeKind(I.getValue())) {
|
|
|
|
FS->RootRelative = *Kind;
|
|
|
|
} else {
|
|
|
|
error(I.getValue(), "expected valid root-relative kind");
|
|
|
|
return false;
|
|
|
|
}
|
2014-02-21 23:39:37 +00:00
|
|
|
} else {
|
|
|
|
llvm_unreachable("key missing from Keys");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Stream.failed())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!checkMissingKeys(Top, Keys))
|
|
|
|
return false;
|
[VFS] Reapply #2: Reconstruct the VFS overlay tree for more accurate lookup
Reapply r269100 and r269270, reverted due to
https://llvm.org/bugs/show_bug.cgi?id=27725. Isolate the testcase that
corresponds to the new feature side of this commit and skip it on
windows hosts until we find why it does not work on these platforms.
Original commit message:
The way we currently build the internal VFS overlay representation leads
to inefficient path search and might yield wrong answers when asked for
recursive or regular directory iteration.
Currently, when reading an YAML file, each YAML root entry is placed
inside a new root in the filesystem overlay. In the crash reproducer, a
simple "@import Foundation" currently maps to 43 roots, and when looking
up paths, we traverse a directory tree for each of these different
roots, until we find a match (or don't). This has two consequences:
- It's slow.
- Directory iteration gives incomplete results since it only return
results within one root - since contents of the same directory can be
declared inside different roots, the result isn't accurate.
This is in part fault of the way we currently write out the YAML file
when emitting the crash reproducer - we could generate only one root and
that would make it fast and correct again. However, we should not rely
on how the client writes the YAML, but provide a good internal
representation regardless.
Build a proper virtual directory tree out of the YAML representation,
allowing faster search and proper iteration. Besides the crash
reproducer, this potentially benefits other VFS clients.
llvm-svn: 269327
2016-05-12 19:13:07 +00:00
|
|
|
|
|
|
|
// Now that we sucessefully parsed the YAML file, canonicalize the internal
|
|
|
|
// representation to a proper directory tree so that we can search faster
|
|
|
|
// inside the VFS.
|
2018-03-28 22:09:09 +00:00
|
|
|
for (auto &E : RootEntries)
|
[VFS] Reapply #2: Reconstruct the VFS overlay tree for more accurate lookup
Reapply r269100 and r269270, reverted due to
https://llvm.org/bugs/show_bug.cgi?id=27725. Isolate the testcase that
corresponds to the new feature side of this commit and skip it on
windows hosts until we find why it does not work on these platforms.
Original commit message:
The way we currently build the internal VFS overlay representation leads
to inefficient path search and might yield wrong answers when asked for
recursive or regular directory iteration.
Currently, when reading an YAML file, each YAML root entry is placed
inside a new root in the filesystem overlay. In the crash reproducer, a
simple "@import Foundation" currently maps to 43 roots, and when looking
up paths, we traverse a directory tree for each of these different
roots, until we find a match (or don't). This has two consequences:
- It's slow.
- Directory iteration gives incomplete results since it only return
results within one root - since contents of the same directory can be
declared inside different roots, the result isn't accurate.
This is in part fault of the way we currently write out the YAML file
when emitting the crash reproducer - we could generate only one root and
that would make it fast and correct again. However, we should not rely
on how the client writes the YAML, but provide a good internal
representation regardless.
Build a proper virtual directory tree out of the YAML representation,
allowing faster search and proper iteration. Besides the crash
reproducer, this potentially benefits other VFS clients.
llvm-svn: 269327
2016-05-12 19:13:07 +00:00
|
|
|
uniqueOverlayTree(FS, E.get());
|
|
|
|
|
2014-02-21 23:39:37 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-12-08 14:58:46 -08:00
|
|
|
std::unique_ptr<RedirectingFileSystem>
|
Reapply [2] [VFS] Add 'overlay-relative' field to YAML files
This reapplies r261552 and r263748. Fixed testcase to reapply.
The VFS overlay mapping between virtual paths and real paths is done through
the 'external-contents' entries in YAML files, which contains hardcoded paths
to the real files.
When a module compilation crashes, headers are dumped into <name>.cache/vfs
directory and are mapped via the <name>.cache/vfs/vfs.yaml. The script
generated for reproduction uses -ivfsoverlay pointing to file to gather the
mapping between virtual paths and files inside <name>.cache/vfs. Currently, we
are only capable of reproducing such crashes in the same machine as they
happen, because of the hardcoded paths in 'external-contents'.
To be able to reproduce a crash in another machine, this patch introduces a new
option in the VFS yaml file called 'overlay-relative'. When it's equal to
'true' it means that the provided path to the YAML file through the
-ivfsoverlay option should also be used to prefix the final path for every
'external-contents'.
Example, given the invocation snippet "... -ivfsoverlay
<name>.cache/vfs/vfs.yaml" and the following entry in the yaml file:
"overlay-relative": "true",
"roots": [
...
"type": "directory",
"name": "/usr/include",
"contents": [
{
"type": "file",
"name": "stdio.h",
"external-contents": "/usr/include/stdio.h"
},
...
Here, a file manager request for virtual "/usr/include/stdio.h", that will map
into real path "/<absolute_path_to>/<name>.cache/vfs/usr/include/stdio.h.
This is a useful feature for debugging module crashes in machines other than
the one where the error happened.
Differential Revision: http://reviews.llvm.org/D17457
rdar://problem/24499339
llvm-svn: 263893
2016-03-20 02:08:48 +00:00
|
|
|
RedirectingFileSystem::create(std::unique_ptr<MemoryBuffer> Buffer,
|
|
|
|
SourceMgr::DiagHandlerTy DiagHandler,
|
|
|
|
StringRef YAMLFilePath, void *DiagContext,
|
|
|
|
IntrusiveRefCntPtr<FileSystem> ExternalFS) {
|
2014-02-21 23:39:37 +00:00
|
|
|
SourceMgr SM;
|
2014-08-27 19:03:27 +00:00
|
|
|
yaml::Stream Stream(Buffer->getMemBufferRef(), SM);
|
2014-02-21 23:39:37 +00:00
|
|
|
|
2014-02-24 20:56:37 +00:00
|
|
|
SM.setDiagHandler(DiagHandler, DiagContext);
|
2014-02-21 23:39:37 +00:00
|
|
|
yaml::document_iterator DI = Stream.begin();
|
|
|
|
yaml::Node *Root = DI->getRoot();
|
|
|
|
if (DI == Stream.end() || !Root) {
|
|
|
|
SM.PrintMessage(SMLoc(), SourceMgr::DK_Error, "expected root node");
|
2014-05-08 06:41:40 +00:00
|
|
|
return nullptr;
|
2014-02-21 23:39:37 +00:00
|
|
|
}
|
|
|
|
|
2015-10-07 10:05:44 +00:00
|
|
|
RedirectingFileSystemParser P(Stream);
|
2014-02-21 23:39:37 +00:00
|
|
|
|
2015-10-07 10:05:44 +00:00
|
|
|
std::unique_ptr<RedirectingFileSystem> FS(
|
2019-10-15 23:08:57 +00:00
|
|
|
new RedirectingFileSystem(ExternalFS));
|
Reapply [2] [VFS] Add 'overlay-relative' field to YAML files
This reapplies r261552 and r263748. Fixed testcase to reapply.
The VFS overlay mapping between virtual paths and real paths is done through
the 'external-contents' entries in YAML files, which contains hardcoded paths
to the real files.
When a module compilation crashes, headers are dumped into <name>.cache/vfs
directory and are mapped via the <name>.cache/vfs/vfs.yaml. The script
generated for reproduction uses -ivfsoverlay pointing to file to gather the
mapping between virtual paths and files inside <name>.cache/vfs. Currently, we
are only capable of reproducing such crashes in the same machine as they
happen, because of the hardcoded paths in 'external-contents'.
To be able to reproduce a crash in another machine, this patch introduces a new
option in the VFS yaml file called 'overlay-relative'. When it's equal to
'true' it means that the provided path to the YAML file through the
-ivfsoverlay option should also be used to prefix the final path for every
'external-contents'.
Example, given the invocation snippet "... -ivfsoverlay
<name>.cache/vfs/vfs.yaml" and the following entry in the yaml file:
"overlay-relative": "true",
"roots": [
...
"type": "directory",
"name": "/usr/include",
"contents": [
{
"type": "file",
"name": "stdio.h",
"external-contents": "/usr/include/stdio.h"
},
...
Here, a file manager request for virtual "/usr/include/stdio.h", that will map
into real path "/<absolute_path_to>/<name>.cache/vfs/usr/include/stdio.h.
This is a useful feature for debugging module crashes in machines other than
the one where the error happened.
Differential Revision: http://reviews.llvm.org/D17457
rdar://problem/24499339
llvm-svn: 263893
2016-03-20 02:08:48 +00:00
|
|
|
|
|
|
|
if (!YAMLFilePath.empty()) {
|
|
|
|
// Use the YAML path from -ivfsoverlay to compute the dir to be prefixed
|
|
|
|
// to each 'external-contents' path.
|
|
|
|
//
|
|
|
|
// Example:
|
|
|
|
// -ivfsoverlay dummy.cache/vfs/vfs.yaml
|
|
|
|
// yields:
|
2022-11-04 16:40:10 -07:00
|
|
|
// FS->OverlayFileDir => /<absolute_path_to>/dummy.cache/vfs
|
Reapply [2] [VFS] Add 'overlay-relative' field to YAML files
This reapplies r261552 and r263748. Fixed testcase to reapply.
The VFS overlay mapping between virtual paths and real paths is done through
the 'external-contents' entries in YAML files, which contains hardcoded paths
to the real files.
When a module compilation crashes, headers are dumped into <name>.cache/vfs
directory and are mapped via the <name>.cache/vfs/vfs.yaml. The script
generated for reproduction uses -ivfsoverlay pointing to file to gather the
mapping between virtual paths and files inside <name>.cache/vfs. Currently, we
are only capable of reproducing such crashes in the same machine as they
happen, because of the hardcoded paths in 'external-contents'.
To be able to reproduce a crash in another machine, this patch introduces a new
option in the VFS yaml file called 'overlay-relative'. When it's equal to
'true' it means that the provided path to the YAML file through the
-ivfsoverlay option should also be used to prefix the final path for every
'external-contents'.
Example, given the invocation snippet "... -ivfsoverlay
<name>.cache/vfs/vfs.yaml" and the following entry in the yaml file:
"overlay-relative": "true",
"roots": [
...
"type": "directory",
"name": "/usr/include",
"contents": [
{
"type": "file",
"name": "stdio.h",
"external-contents": "/usr/include/stdio.h"
},
...
Here, a file manager request for virtual "/usr/include/stdio.h", that will map
into real path "/<absolute_path_to>/<name>.cache/vfs/usr/include/stdio.h.
This is a useful feature for debugging module crashes in machines other than
the one where the error happened.
Differential Revision: http://reviews.llvm.org/D17457
rdar://problem/24499339
llvm-svn: 263893
2016-03-20 02:08:48 +00:00
|
|
|
//
|
|
|
|
SmallString<256> OverlayAbsDir = sys::path::parent_path(YAMLFilePath);
|
|
|
|
std::error_code EC = llvm::sys::fs::make_absolute(OverlayAbsDir);
|
|
|
|
assert(!EC && "Overlay dir final path must be absolute");
|
|
|
|
(void)EC;
|
2022-11-04 16:40:10 -07:00
|
|
|
FS->setOverlayFileDir(OverlayAbsDir);
|
Reapply [2] [VFS] Add 'overlay-relative' field to YAML files
This reapplies r261552 and r263748. Fixed testcase to reapply.
The VFS overlay mapping between virtual paths and real paths is done through
the 'external-contents' entries in YAML files, which contains hardcoded paths
to the real files.
When a module compilation crashes, headers are dumped into <name>.cache/vfs
directory and are mapped via the <name>.cache/vfs/vfs.yaml. The script
generated for reproduction uses -ivfsoverlay pointing to file to gather the
mapping between virtual paths and files inside <name>.cache/vfs. Currently, we
are only capable of reproducing such crashes in the same machine as they
happen, because of the hardcoded paths in 'external-contents'.
To be able to reproduce a crash in another machine, this patch introduces a new
option in the VFS yaml file called 'overlay-relative'. When it's equal to
'true' it means that the provided path to the YAML file through the
-ivfsoverlay option should also be used to prefix the final path for every
'external-contents'.
Example, given the invocation snippet "... -ivfsoverlay
<name>.cache/vfs/vfs.yaml" and the following entry in the yaml file:
"overlay-relative": "true",
"roots": [
...
"type": "directory",
"name": "/usr/include",
"contents": [
{
"type": "file",
"name": "stdio.h",
"external-contents": "/usr/include/stdio.h"
},
...
Here, a file manager request for virtual "/usr/include/stdio.h", that will map
into real path "/<absolute_path_to>/<name>.cache/vfs/usr/include/stdio.h.
This is a useful feature for debugging module crashes in machines other than
the one where the error happened.
Differential Revision: http://reviews.llvm.org/D17457
rdar://problem/24499339
llvm-svn: 263893
2016-03-20 02:08:48 +00:00
|
|
|
}
|
|
|
|
|
2014-02-21 23:39:37 +00:00
|
|
|
if (!P.parse(Root, FS.get()))
|
2014-05-08 06:41:40 +00:00
|
|
|
return nullptr;
|
2014-02-21 23:39:37 +00:00
|
|
|
|
2020-12-08 14:58:46 -08:00
|
|
|
return FS;
|
2014-02-21 23:39:37 +00:00
|
|
|
}
|
|
|
|
|
2020-11-11 23:03:38 -05:00
|
|
|
std::unique_ptr<RedirectingFileSystem> RedirectingFileSystem::create(
|
|
|
|
ArrayRef<std::pair<std::string, std::string>> RemappedFiles,
|
|
|
|
bool UseExternalNames, FileSystem &ExternalFS) {
|
|
|
|
std::unique_ptr<RedirectingFileSystem> FS(
|
|
|
|
new RedirectingFileSystem(&ExternalFS));
|
|
|
|
FS->UseExternalNames = UseExternalNames;
|
|
|
|
|
|
|
|
StringMap<RedirectingFileSystem::Entry *> Entries;
|
|
|
|
|
|
|
|
for (auto &Mapping : llvm::reverse(RemappedFiles)) {
|
|
|
|
SmallString<128> From = StringRef(Mapping.first);
|
|
|
|
SmallString<128> To = StringRef(Mapping.second);
|
|
|
|
{
|
|
|
|
auto EC = ExternalFS.makeAbsolute(From);
|
|
|
|
(void)EC;
|
|
|
|
assert(!EC && "Could not make absolute path");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if we've already mapped this file. The first one we see (in the
|
|
|
|
// reverse iteration) wins.
|
|
|
|
RedirectingFileSystem::Entry *&ToEntry = Entries[From];
|
|
|
|
if (ToEntry)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Add parent directories.
|
|
|
|
RedirectingFileSystem::Entry *Parent = nullptr;
|
|
|
|
StringRef FromDirectory = llvm::sys::path::parent_path(From);
|
|
|
|
for (auto I = llvm::sys::path::begin(FromDirectory),
|
|
|
|
E = llvm::sys::path::end(FromDirectory);
|
|
|
|
I != E; ++I) {
|
|
|
|
Parent = RedirectingFileSystemParser::lookupOrCreateEntry(FS.get(), *I,
|
|
|
|
Parent);
|
|
|
|
}
|
|
|
|
assert(Parent && "File without a directory?");
|
|
|
|
{
|
|
|
|
auto EC = ExternalFS.makeAbsolute(To);
|
|
|
|
(void)EC;
|
|
|
|
assert(!EC && "Could not make absolute path");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add the file.
|
2021-01-16 11:44:14 +10:00
|
|
|
auto NewFile = std::make_unique<RedirectingFileSystem::FileEntry>(
|
|
|
|
llvm::sys::path::filename(From), To,
|
2021-01-15 17:33:52 +10:00
|
|
|
UseExternalNames ? RedirectingFileSystem::NK_External
|
|
|
|
: RedirectingFileSystem::NK_Virtual);
|
2020-11-11 23:03:38 -05:00
|
|
|
ToEntry = NewFile.get();
|
2021-01-16 11:44:14 +10:00
|
|
|
cast<RedirectingFileSystem::DirectoryEntry>(Parent)->addContent(
|
2020-11-11 23:03:38 -05:00
|
|
|
std::move(NewFile));
|
|
|
|
}
|
|
|
|
|
|
|
|
return FS;
|
|
|
|
}
|
|
|
|
|
2021-01-15 17:33:52 +10:00
|
|
|
RedirectingFileSystem::LookupResult::LookupResult(
|
|
|
|
Entry *E, sys::path::const_iterator Start, sys::path::const_iterator End)
|
|
|
|
: E(E) {
|
|
|
|
assert(E != nullptr);
|
|
|
|
// If the matched entry is a DirectoryRemapEntry, set ExternalRedirect to the
|
|
|
|
// path of the directory it maps to in the external file system plus any
|
|
|
|
// remaining path components in the provided iterator.
|
|
|
|
if (auto *DRE = dyn_cast<RedirectingFileSystem::DirectoryRemapEntry>(E)) {
|
|
|
|
SmallString<256> Redirect(DRE->getExternalContentsPath());
|
|
|
|
sys::path::append(Redirect, Start, End,
|
|
|
|
getExistingStyle(DRE->getExternalContentsPath()));
|
|
|
|
ExternalRedirect = std::string(Redirect);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-10 10:10:38 -07:00
|
|
|
void RedirectingFileSystem::LookupResult::getPath(
|
|
|
|
llvm::SmallVectorImpl<char> &Result) const {
|
|
|
|
Result.clear();
|
|
|
|
for (Entry *Parent : Parents)
|
|
|
|
llvm::sys::path::append(Result, Parent->getName());
|
|
|
|
llvm::sys::path::append(Result, E->getName());
|
|
|
|
}
|
|
|
|
|
2024-03-15 09:01:41 -07:00
|
|
|
std::error_code RedirectingFileSystem::makeCanonicalForLookup(
|
|
|
|
SmallVectorImpl<char> &Path) const {
|
2015-10-05 13:55:20 +00:00
|
|
|
if (std::error_code EC = makeAbsolute(Path))
|
2014-03-04 22:34:50 +00:00
|
|
|
return EC;
|
2014-02-21 23:39:37 +00:00
|
|
|
|
2021-01-22 13:51:59 -08:00
|
|
|
llvm::SmallString<256> CanonicalPath =
|
|
|
|
canonicalize(StringRef(Path.data(), Path.size()));
|
|
|
|
if (CanonicalPath.empty())
|
2014-06-13 17:20:50 +00:00
|
|
|
return make_error_code(llvm::errc::invalid_argument);
|
2014-02-21 23:39:37 +00:00
|
|
|
|
2021-01-22 13:51:59 -08:00
|
|
|
Path.assign(CanonicalPath.begin(), CanonicalPath.end());
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2021-01-15 17:33:52 +10:00
|
|
|
ErrorOr<RedirectingFileSystem::LookupResult>
|
2021-01-22 13:51:59 -08:00
|
|
|
RedirectingFileSystem::lookupPath(StringRef Path) const {
|
2024-03-15 09:01:41 -07:00
|
|
|
llvm::SmallString<128> CanonicalPath(Path);
|
|
|
|
if (std::error_code EC = makeCanonicalForLookup(CanonicalPath))
|
|
|
|
return EC;
|
|
|
|
|
2024-01-30 15:39:18 -08:00
|
|
|
// RedirectOnly means the VFS is always used.
|
|
|
|
if (UsageTrackingActive && Redirection == RedirectKind::RedirectOnly)
|
|
|
|
HasBeenUsed = true;
|
|
|
|
|
2024-03-15 09:01:41 -07:00
|
|
|
sys::path::const_iterator Start = sys::path::begin(CanonicalPath);
|
|
|
|
sys::path::const_iterator End = sys::path::end(CanonicalPath);
|
2023-07-10 10:10:38 -07:00
|
|
|
llvm::SmallVector<Entry *, 32> Entries;
|
2018-03-28 22:09:09 +00:00
|
|
|
for (const auto &Root : Roots) {
|
2021-01-15 17:33:52 +10:00
|
|
|
ErrorOr<RedirectingFileSystem::LookupResult> Result =
|
2023-07-10 10:10:38 -07:00
|
|
|
lookupPathImpl(Start, End, Root.get(), Entries);
|
2024-01-30 15:39:18 -08:00
|
|
|
if (UsageTrackingActive && Result && isa<RemapEntry>(Result->E))
|
|
|
|
HasBeenUsed = true;
|
2023-07-10 10:10:38 -07:00
|
|
|
if (Result || Result.getError() != llvm::errc::no_such_file_or_directory) {
|
|
|
|
Result->Parents = std::move(Entries);
|
2014-02-21 23:39:37 +00:00
|
|
|
return Result;
|
2023-07-10 10:10:38 -07:00
|
|
|
}
|
2014-02-21 23:39:37 +00:00
|
|
|
}
|
2014-06-13 17:20:50 +00:00
|
|
|
return make_error_code(llvm::errc::no_such_file_or_directory);
|
2014-02-21 23:39:37 +00:00
|
|
|
}
|
|
|
|
|
2021-01-15 17:33:52 +10:00
|
|
|
ErrorOr<RedirectingFileSystem::LookupResult>
|
|
|
|
RedirectingFileSystem::lookupPathImpl(
|
|
|
|
sys::path::const_iterator Start, sys::path::const_iterator End,
|
2023-07-10 10:10:38 -07:00
|
|
|
RedirectingFileSystem::Entry *From,
|
|
|
|
llvm::SmallVectorImpl<Entry *> &Entries) const {
|
2016-03-17 02:20:43 +00:00
|
|
|
assert(!isTraversalComponent(*Start) &&
|
|
|
|
!isTraversalComponent(From->getName()) &&
|
|
|
|
"Paths should not contain traversal components");
|
2014-03-04 22:34:50 +00:00
|
|
|
|
2016-03-30 23:54:00 +00:00
|
|
|
StringRef FromName = From->getName();
|
2014-02-21 23:39:37 +00:00
|
|
|
|
2016-03-30 23:54:00 +00:00
|
|
|
// Forward the search to the next component in case this is an empty one.
|
|
|
|
if (!FromName.empty()) {
|
2019-11-07 10:50:33 -08:00
|
|
|
if (!pathComponentMatches(*Start, FromName))
|
2016-03-30 23:54:00 +00:00
|
|
|
return make_error_code(llvm::errc::no_such_file_or_directory);
|
2014-02-21 23:39:37 +00:00
|
|
|
|
2016-03-30 23:54:00 +00:00
|
|
|
++Start;
|
|
|
|
|
|
|
|
if (Start == End) {
|
|
|
|
// Match!
|
2021-01-15 17:33:52 +10:00
|
|
|
return LookupResult(From, Start, End);
|
2016-03-30 23:54:00 +00:00
|
|
|
}
|
2014-02-21 23:39:37 +00:00
|
|
|
}
|
|
|
|
|
2021-01-15 17:33:52 +10:00
|
|
|
if (isa<RedirectingFileSystem::FileEntry>(From))
|
2014-06-13 17:20:50 +00:00
|
|
|
return make_error_code(llvm::errc::not_a_directory);
|
2014-02-21 23:39:37 +00:00
|
|
|
|
2021-01-15 17:33:52 +10:00
|
|
|
if (isa<RedirectingFileSystem::DirectoryRemapEntry>(From))
|
|
|
|
return LookupResult(From, Start, End);
|
|
|
|
|
|
|
|
auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(From);
|
2019-01-15 22:36:41 +00:00
|
|
|
for (const std::unique_ptr<RedirectingFileSystem::Entry> &DirEntry :
|
2015-10-07 10:05:44 +00:00
|
|
|
llvm::make_range(DE->contents_begin(), DE->contents_end())) {
|
2023-07-10 10:10:38 -07:00
|
|
|
Entries.push_back(From);
|
2021-01-15 17:33:52 +10:00
|
|
|
ErrorOr<RedirectingFileSystem::LookupResult> Result =
|
2023-07-10 10:10:38 -07:00
|
|
|
lookupPathImpl(Start, End, DirEntry.get(), Entries);
|
2014-06-13 17:20:50 +00:00
|
|
|
if (Result || Result.getError() != llvm::errc::no_such_file_or_directory)
|
2014-02-21 23:39:37 +00:00
|
|
|
return Result;
|
2023-07-10 10:10:38 -07:00
|
|
|
Entries.pop_back();
|
2014-02-21 23:39:37 +00:00
|
|
|
}
|
2019-11-07 10:50:33 -08:00
|
|
|
|
2014-06-13 17:20:50 +00:00
|
|
|
return make_error_code(llvm::errc::no_such_file_or_directory);
|
2014-02-21 23:39:37 +00:00
|
|
|
}
|
|
|
|
|
2021-11-13 10:13:38 -08:00
|
|
|
static Status getRedirectedFileStatus(const Twine &OriginalPath,
|
|
|
|
bool UseExternalNames,
|
2015-12-10 23:41:39 +00:00
|
|
|
Status ExternalStatus) {
|
2022-04-11 14:50:28 -07:00
|
|
|
// The path has been mapped by some nested VFS and exposes an external path,
|
|
|
|
// don't override it with the original path.
|
|
|
|
if (ExternalStatus.ExposesExternalVFSPath)
|
|
|
|
return ExternalStatus;
|
|
|
|
|
2015-12-10 23:41:39 +00:00
|
|
|
Status S = ExternalStatus;
|
|
|
|
if (!UseExternalNames)
|
2021-11-13 10:13:38 -08:00
|
|
|
S = Status::copyWithNewName(S, OriginalPath);
|
2022-04-11 14:50:28 -07:00
|
|
|
else
|
|
|
|
S.ExposesExternalVFSPath = true;
|
2015-12-10 23:41:39 +00:00
|
|
|
return S;
|
|
|
|
}
|
|
|
|
|
2021-01-15 17:33:52 +10:00
|
|
|
ErrorOr<Status> RedirectingFileSystem::status(
|
2024-03-15 09:01:41 -07:00
|
|
|
const Twine &LookupPath, const Twine &OriginalPath,
|
2021-11-13 10:13:38 -08:00
|
|
|
const RedirectingFileSystem::LookupResult &Result) {
|
2022-12-16 08:49:10 +00:00
|
|
|
if (std::optional<StringRef> ExtRedirect = Result.getExternalRedirect()) {
|
2024-03-15 09:01:41 -07:00
|
|
|
SmallString<256> RemappedPath((*ExtRedirect).str());
|
|
|
|
if (std::error_code EC = makeAbsolute(RemappedPath))
|
2021-11-13 10:13:38 -08:00
|
|
|
return EC;
|
|
|
|
|
2024-03-15 09:01:41 -07:00
|
|
|
ErrorOr<Status> S = ExternalFS->status(RemappedPath);
|
2021-01-15 17:33:52 +10:00
|
|
|
if (!S)
|
|
|
|
return S;
|
2021-11-13 10:13:38 -08:00
|
|
|
S = Status::copyWithNewName(*S, *ExtRedirect);
|
2021-01-15 17:33:52 +10:00
|
|
|
auto *RE = cast<RedirectingFileSystem::RemapEntry>(Result.E);
|
2021-11-13 10:13:38 -08:00
|
|
|
return getRedirectedFileStatus(OriginalPath,
|
|
|
|
RE->useExternalName(UseExternalNames), *S);
|
2014-02-21 23:39:37 +00:00
|
|
|
}
|
2021-01-15 17:33:52 +10:00
|
|
|
|
|
|
|
auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(Result.E);
|
2024-03-15 09:01:41 -07:00
|
|
|
return Status::copyWithNewName(DE->getStatus(), LookupPath);
|
2021-11-13 09:34:30 -08:00
|
|
|
}
|
2021-01-22 13:51:59 -08:00
|
|
|
|
2021-11-13 10:13:38 -08:00
|
|
|
ErrorOr<Status>
|
2024-03-15 09:01:41 -07:00
|
|
|
RedirectingFileSystem::getExternalStatus(const Twine &LookupPath,
|
2021-11-13 10:13:38 -08:00
|
|
|
const Twine &OriginalPath) const {
|
2024-03-15 09:01:41 -07:00
|
|
|
auto Result = ExternalFS->status(LookupPath);
|
2022-04-11 14:50:28 -07:00
|
|
|
|
|
|
|
// The path has been mapped by some nested VFS, don't override it with the
|
|
|
|
// original path.
|
|
|
|
if (!Result || Result->ExposesExternalVFSPath)
|
|
|
|
return Result;
|
|
|
|
return Status::copyWithNewName(Result.get(), OriginalPath);
|
2021-11-13 10:13:38 -08:00
|
|
|
}
|
2021-11-13 09:34:30 -08:00
|
|
|
|
2021-11-13 10:13:38 -08:00
|
|
|
ErrorOr<Status> RedirectingFileSystem::status(const Twine &OriginalPath) {
|
2024-03-15 09:01:41 -07:00
|
|
|
SmallString<256> Path;
|
|
|
|
OriginalPath.toVector(Path);
|
2021-11-13 10:13:38 -08:00
|
|
|
|
2024-03-15 09:01:41 -07:00
|
|
|
if (std::error_code EC = makeAbsolute(Path))
|
2021-01-22 13:51:59 -08:00
|
|
|
return EC;
|
|
|
|
|
2022-02-03 12:53:22 -08:00
|
|
|
if (Redirection == RedirectKind::Fallback) {
|
|
|
|
// Attempt to find the original file first, only falling back to the
|
|
|
|
// mapped file if that fails.
|
2024-03-15 09:01:41 -07:00
|
|
|
ErrorOr<Status> S = getExternalStatus(Path, OriginalPath);
|
2022-02-03 12:53:22 -08:00
|
|
|
if (S)
|
|
|
|
return S;
|
|
|
|
}
|
|
|
|
|
2024-03-15 09:01:41 -07:00
|
|
|
ErrorOr<RedirectingFileSystem::LookupResult> Result = lookupPath(Path);
|
2018-10-26 22:14:33 +00:00
|
|
|
if (!Result) {
|
2022-02-03 12:53:22 -08:00
|
|
|
// Was not able to map file, fallthrough to using the original path if
|
|
|
|
// that was the specified redirection type.
|
|
|
|
if (Redirection == RedirectKind::Fallthrough &&
|
|
|
|
isFileNotFound(Result.getError()))
|
2024-03-15 09:01:41 -07:00
|
|
|
return getExternalStatus(Path, OriginalPath);
|
2014-06-24 19:37:16 +00:00
|
|
|
return Result.getError();
|
2018-10-26 22:14:33 +00:00
|
|
|
}
|
2021-01-15 17:33:52 +10:00
|
|
|
|
2024-03-15 09:01:41 -07:00
|
|
|
ErrorOr<Status> S = status(Path, OriginalPath, *Result);
|
2022-02-03 12:53:22 -08:00
|
|
|
if (!S && Redirection == RedirectKind::Fallthrough &&
|
|
|
|
isFileNotFound(S.getError(), Result->E)) {
|
|
|
|
// Mapped the file but it wasn't found in the underlying filesystem,
|
|
|
|
// fallthrough to using the original path if that was the specified
|
|
|
|
// redirection type.
|
2024-03-15 09:01:41 -07:00
|
|
|
return getExternalStatus(Path, OriginalPath);
|
2021-11-13 10:13:38 -08:00
|
|
|
}
|
|
|
|
|
2021-01-15 17:33:52 +10:00
|
|
|
return S;
|
2014-06-24 19:37:16 +00:00
|
|
|
}
|
|
|
|
|
2024-04-12 13:34:47 -07:00
|
|
|
bool RedirectingFileSystem::exists(const Twine &OriginalPath) {
|
|
|
|
SmallString<256> Path;
|
|
|
|
OriginalPath.toVector(Path);
|
|
|
|
|
|
|
|
if (makeAbsolute(Path))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (Redirection == RedirectKind::Fallback) {
|
|
|
|
// Attempt to find the original file first, only falling back to the
|
|
|
|
// mapped file if that fails.
|
|
|
|
if (ExternalFS->exists(Path))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
ErrorOr<RedirectingFileSystem::LookupResult> Result = lookupPath(Path);
|
|
|
|
if (!Result) {
|
|
|
|
// Was not able to map file, fallthrough to using the original path if
|
|
|
|
// that was the specified redirection type.
|
|
|
|
if (Redirection == RedirectKind::Fallthrough &&
|
|
|
|
isFileNotFound(Result.getError()))
|
|
|
|
return ExternalFS->exists(Path);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::optional<StringRef> ExtRedirect = Result->getExternalRedirect();
|
|
|
|
if (!ExtRedirect) {
|
|
|
|
assert(isa<RedirectingFileSystem::DirectoryEntry>(Result->E));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
SmallString<256> RemappedPath((*ExtRedirect).str());
|
|
|
|
if (makeAbsolute(RemappedPath))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (ExternalFS->exists(RemappedPath))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (Redirection == RedirectKind::Fallthrough) {
|
|
|
|
// Mapped the file but it wasn't found in the underlying filesystem,
|
|
|
|
// fallthrough to using the original path if that was the specified
|
|
|
|
// redirection type.
|
|
|
|
return ExternalFS->exists(Path);
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-10-05 13:55:09 +00:00
|
|
|
namespace {
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2015-12-10 23:41:39 +00:00
|
|
|
/// Provide a file wrapper with an overriden status.
|
|
|
|
class FileWithFixedStatus : public File {
|
2015-10-05 13:55:09 +00:00
|
|
|
std::unique_ptr<File> InnerFile;
|
2015-12-10 23:41:39 +00:00
|
|
|
Status S;
|
2015-10-05 13:55:09 +00:00
|
|
|
|
|
|
|
public:
|
2015-12-10 23:41:39 +00:00
|
|
|
FileWithFixedStatus(std::unique_ptr<File> InnerFile, Status S)
|
2016-05-27 14:27:13 +00:00
|
|
|
: InnerFile(std::move(InnerFile)), S(std::move(S)) {}
|
2015-12-10 23:41:39 +00:00
|
|
|
|
|
|
|
ErrorOr<Status> status() override { return S; }
|
|
|
|
ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2015-10-05 21:20:19 +00:00
|
|
|
getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
|
|
|
|
bool IsVolatile) override {
|
2015-10-05 13:55:09 +00:00
|
|
|
return InnerFile->getBuffer(Name, FileSize, RequiresNullTerminator,
|
|
|
|
IsVolatile);
|
|
|
|
}
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2015-10-05 13:55:09 +00:00
|
|
|
std::error_code close() override { return InnerFile->close(); }
|
2021-11-13 10:13:38 -08:00
|
|
|
|
|
|
|
void setPath(const Twine &Path) override { S = S.copyWithNewName(S, Path); }
|
2015-10-05 13:55:09 +00:00
|
|
|
};
|
2018-03-28 22:09:09 +00:00
|
|
|
|
|
|
|
} // namespace
|
2015-10-05 13:55:09 +00:00
|
|
|
|
2015-10-07 10:05:44 +00:00
|
|
|
ErrorOr<std::unique_ptr<File>>
|
2021-11-13 10:13:38 -08:00
|
|
|
File::getWithPath(ErrorOr<std::unique_ptr<File>> Result, const Twine &P) {
|
2022-04-11 14:50:28 -07:00
|
|
|
// See \c getRedirectedFileStatus - don't update path if it's exposing an
|
|
|
|
// external path.
|
|
|
|
if (!Result || (*Result)->status()->ExposesExternalVFSPath)
|
2021-11-13 10:13:38 -08:00
|
|
|
return Result;
|
2021-11-13 09:34:30 -08:00
|
|
|
|
2021-11-13 10:13:38 -08:00
|
|
|
ErrorOr<std::unique_ptr<File>> F = std::move(*Result);
|
|
|
|
auto Name = F->get()->getName();
|
|
|
|
if (Name && Name.get() != P.str())
|
|
|
|
F->get()->setPath(P);
|
|
|
|
return F;
|
|
|
|
}
|
|
|
|
|
|
|
|
ErrorOr<std::unique_ptr<File>>
|
|
|
|
RedirectingFileSystem::openFileForRead(const Twine &OriginalPath) {
|
2024-03-15 09:01:41 -07:00
|
|
|
SmallString<256> Path;
|
|
|
|
OriginalPath.toVector(Path);
|
2021-11-13 10:13:38 -08:00
|
|
|
|
2024-03-15 09:01:41 -07:00
|
|
|
if (std::error_code EC = makeAbsolute(Path))
|
2021-01-22 13:51:59 -08:00
|
|
|
return EC;
|
|
|
|
|
2022-02-03 12:53:22 -08:00
|
|
|
if (Redirection == RedirectKind::Fallback) {
|
|
|
|
// Attempt to find the original file first, only falling back to the
|
|
|
|
// mapped file if that fails.
|
2024-03-15 09:01:41 -07:00
|
|
|
auto F = File::getWithPath(ExternalFS->openFileForRead(Path), OriginalPath);
|
2022-02-03 12:53:22 -08:00
|
|
|
if (F)
|
|
|
|
return F;
|
|
|
|
}
|
|
|
|
|
2024-03-15 09:01:41 -07:00
|
|
|
ErrorOr<RedirectingFileSystem::LookupResult> Result = lookupPath(Path);
|
2021-01-15 17:33:52 +10:00
|
|
|
if (!Result) {
|
2022-02-03 12:53:22 -08:00
|
|
|
// Was not able to map file, fallthrough to using the original path if
|
|
|
|
// that was the specified redirection type.
|
|
|
|
if (Redirection == RedirectKind::Fallthrough &&
|
|
|
|
isFileNotFound(Result.getError()))
|
2024-03-15 09:01:41 -07:00
|
|
|
return File::getWithPath(ExternalFS->openFileForRead(Path), OriginalPath);
|
2021-01-15 17:33:52 +10:00
|
|
|
return Result.getError();
|
2018-10-26 22:14:33 +00:00
|
|
|
}
|
2014-02-21 23:39:37 +00:00
|
|
|
|
2021-01-15 17:33:52 +10:00
|
|
|
if (!Result->getExternalRedirect()) // FIXME: errc::not_a_file?
|
2014-06-13 17:20:50 +00:00
|
|
|
return make_error_code(llvm::errc::invalid_argument);
|
2014-02-21 23:39:37 +00:00
|
|
|
|
2021-01-15 17:33:52 +10:00
|
|
|
StringRef ExtRedirect = *Result->getExternalRedirect();
|
2024-03-15 09:01:41 -07:00
|
|
|
SmallString<256> RemappedPath(ExtRedirect.str());
|
|
|
|
if (std::error_code EC = makeAbsolute(RemappedPath))
|
2021-11-13 10:13:38 -08:00
|
|
|
return EC;
|
|
|
|
|
2021-01-15 17:33:52 +10:00
|
|
|
auto *RE = cast<RedirectingFileSystem::RemapEntry>(Result->E);
|
2014-02-28 21:16:07 +00:00
|
|
|
|
2024-03-15 09:01:41 -07:00
|
|
|
auto ExternalFile =
|
|
|
|
File::getWithPath(ExternalFS->openFileForRead(RemappedPath), ExtRedirect);
|
2021-01-15 17:33:52 +10:00
|
|
|
if (!ExternalFile) {
|
2022-02-03 12:53:22 -08:00
|
|
|
if (Redirection == RedirectKind::Fallthrough &&
|
|
|
|
isFileNotFound(ExternalFile.getError(), Result->E)) {
|
|
|
|
// Mapped the file but it wasn't found in the underlying filesystem,
|
|
|
|
// fallthrough to using the original path if that was the specified
|
|
|
|
// redirection type.
|
2024-03-15 09:01:41 -07:00
|
|
|
return File::getWithPath(ExternalFS->openFileForRead(Path), OriginalPath);
|
2022-02-03 12:53:22 -08:00
|
|
|
}
|
2021-01-15 17:33:52 +10:00
|
|
|
return ExternalFile;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto ExternalStatus = (*ExternalFile)->status();
|
2015-12-10 23:41:39 +00:00
|
|
|
if (!ExternalStatus)
|
|
|
|
return ExternalStatus.getError();
|
2014-02-28 21:16:07 +00:00
|
|
|
|
2022-02-03 12:53:22 -08:00
|
|
|
// Otherwise, the file was successfully remapped. Mark it as such. Also
|
|
|
|
// replace the underlying path if the external name is being used.
|
2021-01-15 17:33:52 +10:00
|
|
|
Status S = getRedirectedFileStatus(
|
2021-11-13 10:13:38 -08:00
|
|
|
OriginalPath, RE->useExternalName(UseExternalNames), *ExternalStatus);
|
2015-12-10 23:41:39 +00:00
|
|
|
return std::unique_ptr<File>(
|
2021-01-15 17:33:52 +10:00
|
|
|
std::make_unique<FileWithFixedStatus>(std::move(*ExternalFile), S));
|
2014-02-21 23:39:37 +00:00
|
|
|
}
|
|
|
|
|
2018-11-16 01:15:54 +00:00
|
|
|
std::error_code
|
2022-02-03 12:53:22 -08:00
|
|
|
RedirectingFileSystem::getRealPath(const Twine &OriginalPath,
|
2024-04-12 10:09:04 -07:00
|
|
|
SmallVectorImpl<char> &Output) {
|
2024-03-15 09:01:41 -07:00
|
|
|
SmallString<256> Path;
|
|
|
|
OriginalPath.toVector(Path);
|
2021-01-22 13:51:59 -08:00
|
|
|
|
2024-03-15 09:01:41 -07:00
|
|
|
if (std::error_code EC = makeAbsolute(Path))
|
2021-01-22 13:51:59 -08:00
|
|
|
return EC;
|
|
|
|
|
2022-02-03 12:53:22 -08:00
|
|
|
if (Redirection == RedirectKind::Fallback) {
|
|
|
|
// Attempt to find the original file first, only falling back to the
|
|
|
|
// mapped file if that fails.
|
2024-03-15 09:01:41 -07:00
|
|
|
std::error_code EC = ExternalFS->getRealPath(Path, Output);
|
2022-02-03 12:53:22 -08:00
|
|
|
if (!EC)
|
|
|
|
return EC;
|
|
|
|
}
|
|
|
|
|
2024-03-15 09:01:41 -07:00
|
|
|
ErrorOr<RedirectingFileSystem::LookupResult> Result = lookupPath(Path);
|
2018-11-16 01:15:54 +00:00
|
|
|
if (!Result) {
|
2022-02-03 12:53:22 -08:00
|
|
|
// Was not able to map file, fallthrough to using the original path if
|
|
|
|
// that was the specified redirection type.
|
|
|
|
if (Redirection == RedirectKind::Fallthrough &&
|
|
|
|
isFileNotFound(Result.getError()))
|
2024-03-15 09:01:41 -07:00
|
|
|
return ExternalFS->getRealPath(Path, Output);
|
2018-11-16 01:15:54 +00:00
|
|
|
return Result.getError();
|
|
|
|
}
|
|
|
|
|
2021-01-15 17:33:52 +10:00
|
|
|
// If we found FileEntry or DirectoryRemapEntry, look up the mapped
|
|
|
|
// path in the external file system.
|
|
|
|
if (auto ExtRedirect = Result->getExternalRedirect()) {
|
|
|
|
auto P = ExternalFS->getRealPath(*ExtRedirect, Output);
|
2022-02-03 12:53:22 -08:00
|
|
|
if (P && Redirection == RedirectKind::Fallthrough &&
|
|
|
|
isFileNotFound(P, Result->E)) {
|
|
|
|
// Mapped the file but it wasn't found in the underlying filesystem,
|
|
|
|
// fallthrough to using the original path if that was the specified
|
|
|
|
// redirection type.
|
2024-03-15 09:01:41 -07:00
|
|
|
return ExternalFS->getRealPath(Path, Output);
|
2021-01-15 17:33:52 +10:00
|
|
|
}
|
|
|
|
return P;
|
2018-11-16 01:15:54 +00:00
|
|
|
}
|
2021-01-15 17:33:52 +10:00
|
|
|
|
2023-07-10 10:10:38 -07:00
|
|
|
// We found a DirectoryEntry, which does not have a single external contents
|
|
|
|
// path. Use the canonical virtual path.
|
|
|
|
if (Redirection == RedirectKind::Fallthrough) {
|
|
|
|
Result->getPath(Output);
|
|
|
|
return {};
|
|
|
|
}
|
2022-02-03 12:53:22 -08:00
|
|
|
return llvm::errc::invalid_argument;
|
2018-11-16 01:15:54 +00:00
|
|
|
}
|
|
|
|
|
2020-12-08 14:58:46 -08:00
|
|
|
std::unique_ptr<FileSystem>
|
2014-08-17 22:12:58 +00:00
|
|
|
vfs::getVFSFromYAML(std::unique_ptr<MemoryBuffer> Buffer,
|
Reapply [2] [VFS] Add 'overlay-relative' field to YAML files
This reapplies r261552 and r263748. Fixed testcase to reapply.
The VFS overlay mapping between virtual paths and real paths is done through
the 'external-contents' entries in YAML files, which contains hardcoded paths
to the real files.
When a module compilation crashes, headers are dumped into <name>.cache/vfs
directory and are mapped via the <name>.cache/vfs/vfs.yaml. The script
generated for reproduction uses -ivfsoverlay pointing to file to gather the
mapping between virtual paths and files inside <name>.cache/vfs. Currently, we
are only capable of reproducing such crashes in the same machine as they
happen, because of the hardcoded paths in 'external-contents'.
To be able to reproduce a crash in another machine, this patch introduces a new
option in the VFS yaml file called 'overlay-relative'. When it's equal to
'true' it means that the provided path to the YAML file through the
-ivfsoverlay option should also be used to prefix the final path for every
'external-contents'.
Example, given the invocation snippet "... -ivfsoverlay
<name>.cache/vfs/vfs.yaml" and the following entry in the yaml file:
"overlay-relative": "true",
"roots": [
...
"type": "directory",
"name": "/usr/include",
"contents": [
{
"type": "file",
"name": "stdio.h",
"external-contents": "/usr/include/stdio.h"
},
...
Here, a file manager request for virtual "/usr/include/stdio.h", that will map
into real path "/<absolute_path_to>/<name>.cache/vfs/usr/include/stdio.h.
This is a useful feature for debugging module crashes in machines other than
the one where the error happened.
Differential Revision: http://reviews.llvm.org/D17457
rdar://problem/24499339
llvm-svn: 263893
2016-03-20 02:08:48 +00:00
|
|
|
SourceMgr::DiagHandlerTy DiagHandler,
|
2018-10-10 13:27:25 +00:00
|
|
|
StringRef YAMLFilePath, void *DiagContext,
|
2014-02-21 23:39:37 +00:00
|
|
|
IntrusiveRefCntPtr<FileSystem> ExternalFS) {
|
2015-10-07 10:05:44 +00:00
|
|
|
return RedirectingFileSystem::create(std::move(Buffer), DiagHandler,
|
2016-06-12 20:05:23 +00:00
|
|
|
YAMLFilePath, DiagContext,
|
|
|
|
std::move(ExternalFS));
|
2014-02-21 23:39:37 +00:00
|
|
|
}
|
|
|
|
|
2019-01-15 22:36:41 +00:00
|
|
|
static void getVFSEntries(RedirectingFileSystem::Entry *SrcE,
|
|
|
|
SmallVectorImpl<StringRef> &Path,
|
2016-12-22 07:06:03 +00:00
|
|
|
SmallVectorImpl<YAMLVFSEntry> &Entries) {
|
|
|
|
auto Kind = SrcE->getKind();
|
2019-01-15 22:36:41 +00:00
|
|
|
if (Kind == RedirectingFileSystem::EK_Directory) {
|
2021-01-16 11:44:14 +10:00
|
|
|
auto *DE = dyn_cast<RedirectingFileSystem::DirectoryEntry>(SrcE);
|
2016-12-22 07:06:03 +00:00
|
|
|
assert(DE && "Must be a directory");
|
2019-01-15 22:36:41 +00:00
|
|
|
for (std::unique_ptr<RedirectingFileSystem::Entry> &SubEntry :
|
2016-12-22 07:06:03 +00:00
|
|
|
llvm::make_range(DE->contents_begin(), DE->contents_end())) {
|
|
|
|
Path.push_back(SubEntry->getName());
|
|
|
|
getVFSEntries(SubEntry.get(), Path, Entries);
|
|
|
|
Path.pop_back();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-01-15 17:33:52 +10:00
|
|
|
if (Kind == RedirectingFileSystem::EK_DirectoryRemap) {
|
|
|
|
auto *DR = dyn_cast<RedirectingFileSystem::DirectoryRemapEntry>(SrcE);
|
|
|
|
assert(DR && "Must be a directory remap");
|
|
|
|
SmallString<128> VPath;
|
|
|
|
for (auto &Comp : Path)
|
|
|
|
llvm::sys::path::append(VPath, Comp);
|
|
|
|
Entries.push_back(
|
|
|
|
YAMLVFSEntry(VPath.c_str(), DR->getExternalContentsPath()));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-01-15 22:36:41 +00:00
|
|
|
assert(Kind == RedirectingFileSystem::EK_File && "Must be a EK_File");
|
2021-01-16 11:44:14 +10:00
|
|
|
auto *FE = dyn_cast<RedirectingFileSystem::FileEntry>(SrcE);
|
2016-12-22 07:06:03 +00:00
|
|
|
assert(FE && "Must be a file");
|
|
|
|
SmallString<128> VPath;
|
|
|
|
for (auto &Comp : Path)
|
|
|
|
llvm::sys::path::append(VPath, Comp);
|
|
|
|
Entries.push_back(YAMLVFSEntry(VPath.c_str(), FE->getExternalContentsPath()));
|
|
|
|
}
|
|
|
|
|
|
|
|
void vfs::collectVFSFromYAML(std::unique_ptr<MemoryBuffer> Buffer,
|
|
|
|
SourceMgr::DiagHandlerTy DiagHandler,
|
|
|
|
StringRef YAMLFilePath,
|
|
|
|
SmallVectorImpl<YAMLVFSEntry> &CollectedEntries,
|
|
|
|
void *DiagContext,
|
|
|
|
IntrusiveRefCntPtr<FileSystem> ExternalFS) {
|
2020-12-08 14:58:46 -08:00
|
|
|
std::unique_ptr<RedirectingFileSystem> VFS = RedirectingFileSystem::create(
|
2016-12-22 07:06:03 +00:00
|
|
|
std::move(Buffer), DiagHandler, YAMLFilePath, DiagContext,
|
|
|
|
std::move(ExternalFS));
|
2021-04-26 17:01:51 -07:00
|
|
|
if (!VFS)
|
|
|
|
return;
|
2021-01-15 17:33:52 +10:00
|
|
|
ErrorOr<RedirectingFileSystem::LookupResult> RootResult =
|
|
|
|
VFS->lookupPath("/");
|
|
|
|
if (!RootResult)
|
2016-12-22 07:06:03 +00:00
|
|
|
return;
|
|
|
|
SmallVector<StringRef, 8> Components;
|
|
|
|
Components.push_back("/");
|
2021-01-15 17:33:52 +10:00
|
|
|
getVFSEntries(RootResult->E, Components, CollectedEntries);
|
2016-12-22 07:06:03 +00:00
|
|
|
}
|
|
|
|
|
2014-02-21 23:39:37 +00:00
|
|
|
UniqueID vfs::getNextVirtualUniqueID() {
|
2014-03-02 17:08:31 +00:00
|
|
|
static std::atomic<unsigned> UID;
|
|
|
|
unsigned ID = ++UID;
|
2014-02-21 23:39:37 +00:00
|
|
|
// The following assumes that uint64_t max will never collide with a real
|
|
|
|
// dev_t value from the OS.
|
|
|
|
return UniqueID(std::numeric_limits<uint64_t>::max(), ID);
|
|
|
|
}
|
2014-05-20 21:43:27 +00:00
|
|
|
|
2020-03-27 15:02:24 -07:00
|
|
|
void YAMLVFSWriter::addEntry(StringRef VirtualPath, StringRef RealPath,
|
|
|
|
bool IsDirectory) {
|
2014-05-20 21:43:27 +00:00
|
|
|
assert(sys::path::is_absolute(VirtualPath) && "virtual path not absolute");
|
|
|
|
assert(sys::path::is_absolute(RealPath) && "real path not absolute");
|
|
|
|
assert(!pathHasTraversal(VirtualPath) && "path traversal is not supported");
|
2020-03-27 15:02:24 -07:00
|
|
|
Mappings.emplace_back(VirtualPath, RealPath, IsDirectory);
|
|
|
|
}
|
|
|
|
|
|
|
|
void YAMLVFSWriter::addFileMapping(StringRef VirtualPath, StringRef RealPath) {
|
|
|
|
addEntry(VirtualPath, RealPath, /*IsDirectory=*/false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void YAMLVFSWriter::addDirectoryMapping(StringRef VirtualPath,
|
|
|
|
StringRef RealPath) {
|
|
|
|
addEntry(VirtualPath, RealPath, /*IsDirectory=*/true);
|
2014-05-20 21:43:27 +00:00
|
|
|
}
|
|
|
|
|
2014-05-21 22:46:51 +00:00
|
|
|
namespace {
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2014-05-21 22:46:51 +00:00
|
|
|
class JSONWriter {
|
|
|
|
llvm::raw_ostream &OS;
|
|
|
|
SmallVector<StringRef, 16> DirStack;
|
2018-03-28 22:09:09 +00:00
|
|
|
|
|
|
|
unsigned getDirIndent() { return 4 * DirStack.size(); }
|
|
|
|
unsigned getFileIndent() { return 4 * (DirStack.size() + 1); }
|
2014-05-21 22:46:51 +00:00
|
|
|
bool containedIn(StringRef Parent, StringRef Path);
|
|
|
|
StringRef containedPart(StringRef Parent, StringRef Path);
|
|
|
|
void startDirectory(StringRef Path);
|
|
|
|
void endDirectory();
|
|
|
|
void writeEntry(StringRef VPath, StringRef RPath);
|
2014-05-20 21:43:27 +00:00
|
|
|
|
2014-05-21 22:46:51 +00:00
|
|
|
public:
|
|
|
|
JSONWriter(llvm::raw_ostream &OS) : OS(OS) {}
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2022-12-16 08:49:10 +00:00
|
|
|
void write(ArrayRef<YAMLVFSEntry> Entries,
|
|
|
|
std::optional<bool> UseExternalNames,
|
|
|
|
std::optional<bool> IsCaseSensitive,
|
|
|
|
std::optional<bool> IsOverlayRelative, StringRef OverlayDir);
|
2014-05-21 22:46:51 +00:00
|
|
|
};
|
2018-03-28 22:09:09 +00:00
|
|
|
|
|
|
|
} // namespace
|
2014-05-20 21:43:27 +00:00
|
|
|
|
2014-05-21 22:46:51 +00:00
|
|
|
bool JSONWriter::containedIn(StringRef Parent, StringRef Path) {
|
2014-05-20 22:12:58 +00:00
|
|
|
using namespace llvm::sys;
|
2018-03-28 22:09:09 +00:00
|
|
|
|
2014-05-20 22:12:58 +00:00
|
|
|
// Compare each path component.
|
|
|
|
auto IParent = path::begin(Parent), EParent = path::end(Parent);
|
|
|
|
for (auto IChild = path::begin(Path), EChild = path::end(Path);
|
|
|
|
IParent != EParent && IChild != EChild; ++IParent, ++IChild) {
|
|
|
|
if (*IParent != *IChild)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// Have we exhausted the parent path?
|
|
|
|
return IParent == EParent;
|
2014-05-20 21:43:27 +00:00
|
|
|
}
|
|
|
|
|
2014-05-21 22:46:51 +00:00
|
|
|
StringRef JSONWriter::containedPart(StringRef Parent, StringRef Path) {
|
|
|
|
assert(!Parent.empty());
|
2014-05-20 21:43:27 +00:00
|
|
|
assert(containedIn(Parent, Path));
|
|
|
|
return Path.slice(Parent.size() + 1, StringRef::npos);
|
|
|
|
}
|
|
|
|
|
2014-05-21 22:46:51 +00:00
|
|
|
void JSONWriter::startDirectory(StringRef Path) {
|
|
|
|
StringRef Name =
|
|
|
|
DirStack.empty() ? Path : containedPart(DirStack.back(), Path);
|
|
|
|
DirStack.push_back(Path);
|
|
|
|
unsigned Indent = getDirIndent();
|
|
|
|
OS.indent(Indent) << "{\n";
|
|
|
|
OS.indent(Indent + 2) << "'type': 'directory',\n";
|
|
|
|
OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(Name) << "\",\n";
|
|
|
|
OS.indent(Indent + 2) << "'contents': [\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
void JSONWriter::endDirectory() {
|
|
|
|
unsigned Indent = getDirIndent();
|
|
|
|
OS.indent(Indent + 2) << "]\n";
|
|
|
|
OS.indent(Indent) << "}";
|
|
|
|
|
|
|
|
DirStack.pop_back();
|
|
|
|
}
|
|
|
|
|
|
|
|
void JSONWriter::writeEntry(StringRef VPath, StringRef RPath) {
|
|
|
|
unsigned Indent = getFileIndent();
|
|
|
|
OS.indent(Indent) << "{\n";
|
|
|
|
OS.indent(Indent + 2) << "'type': 'file',\n";
|
|
|
|
OS.indent(Indent + 2) << "'name': \"" << llvm::yaml::escape(VPath) << "\",\n";
|
|
|
|
OS.indent(Indent + 2) << "'external-contents': \""
|
|
|
|
<< llvm::yaml::escape(RPath) << "\"\n";
|
|
|
|
OS.indent(Indent) << "}";
|
|
|
|
}
|
|
|
|
|
|
|
|
void JSONWriter::write(ArrayRef<YAMLVFSEntry> Entries,
|
2022-12-16 08:49:10 +00:00
|
|
|
std::optional<bool> UseExternalNames,
|
|
|
|
std::optional<bool> IsCaseSensitive,
|
|
|
|
std::optional<bool> IsOverlayRelative,
|
Reapply [2] [VFS] Add 'overlay-relative' field to YAML files
This reapplies r261552 and r263748. Fixed testcase to reapply.
The VFS overlay mapping between virtual paths and real paths is done through
the 'external-contents' entries in YAML files, which contains hardcoded paths
to the real files.
When a module compilation crashes, headers are dumped into <name>.cache/vfs
directory and are mapped via the <name>.cache/vfs/vfs.yaml. The script
generated for reproduction uses -ivfsoverlay pointing to file to gather the
mapping between virtual paths and files inside <name>.cache/vfs. Currently, we
are only capable of reproducing such crashes in the same machine as they
happen, because of the hardcoded paths in 'external-contents'.
To be able to reproduce a crash in another machine, this patch introduces a new
option in the VFS yaml file called 'overlay-relative'. When it's equal to
'true' it means that the provided path to the YAML file through the
-ivfsoverlay option should also be used to prefix the final path for every
'external-contents'.
Example, given the invocation snippet "... -ivfsoverlay
<name>.cache/vfs/vfs.yaml" and the following entry in the yaml file:
"overlay-relative": "true",
"roots": [
...
"type": "directory",
"name": "/usr/include",
"contents": [
{
"type": "file",
"name": "stdio.h",
"external-contents": "/usr/include/stdio.h"
},
...
Here, a file manager request for virtual "/usr/include/stdio.h", that will map
into real path "/<absolute_path_to>/<name>.cache/vfs/usr/include/stdio.h.
This is a useful feature for debugging module crashes in machines other than
the one where the error happened.
Differential Revision: http://reviews.llvm.org/D17457
rdar://problem/24499339
llvm-svn: 263893
2016-03-20 02:08:48 +00:00
|
|
|
StringRef OverlayDir) {
|
2014-05-21 22:46:51 +00:00
|
|
|
using namespace llvm::sys;
|
2014-05-20 21:43:27 +00:00
|
|
|
|
|
|
|
OS << "{\n"
|
|
|
|
" 'version': 0,\n";
|
2022-06-25 21:42:52 -07:00
|
|
|
if (IsCaseSensitive)
|
2022-12-16 22:44:08 +00:00
|
|
|
OS << " 'case-sensitive': '" << (*IsCaseSensitive ? "true" : "false")
|
|
|
|
<< "',\n";
|
2022-06-25 21:42:52 -07:00
|
|
|
if (UseExternalNames)
|
2022-12-16 22:44:08 +00:00
|
|
|
OS << " 'use-external-names': '" << (*UseExternalNames ? "true" : "false")
|
|
|
|
<< "',\n";
|
Reapply [2] [VFS] Add 'overlay-relative' field to YAML files
This reapplies r261552 and r263748. Fixed testcase to reapply.
The VFS overlay mapping between virtual paths and real paths is done through
the 'external-contents' entries in YAML files, which contains hardcoded paths
to the real files.
When a module compilation crashes, headers are dumped into <name>.cache/vfs
directory and are mapped via the <name>.cache/vfs/vfs.yaml. The script
generated for reproduction uses -ivfsoverlay pointing to file to gather the
mapping between virtual paths and files inside <name>.cache/vfs. Currently, we
are only capable of reproducing such crashes in the same machine as they
happen, because of the hardcoded paths in 'external-contents'.
To be able to reproduce a crash in another machine, this patch introduces a new
option in the VFS yaml file called 'overlay-relative'. When it's equal to
'true' it means that the provided path to the YAML file through the
-ivfsoverlay option should also be used to prefix the final path for every
'external-contents'.
Example, given the invocation snippet "... -ivfsoverlay
<name>.cache/vfs/vfs.yaml" and the following entry in the yaml file:
"overlay-relative": "true",
"roots": [
...
"type": "directory",
"name": "/usr/include",
"contents": [
{
"type": "file",
"name": "stdio.h",
"external-contents": "/usr/include/stdio.h"
},
...
Here, a file manager request for virtual "/usr/include/stdio.h", that will map
into real path "/<absolute_path_to>/<name>.cache/vfs/usr/include/stdio.h.
This is a useful feature for debugging module crashes in machines other than
the one where the error happened.
Differential Revision: http://reviews.llvm.org/D17457
rdar://problem/24499339
llvm-svn: 263893
2016-03-20 02:08:48 +00:00
|
|
|
bool UseOverlayRelative = false;
|
2022-06-25 21:42:52 -07:00
|
|
|
if (IsOverlayRelative) {
|
2022-12-16 22:44:08 +00:00
|
|
|
UseOverlayRelative = *IsOverlayRelative;
|
2018-10-10 13:27:25 +00:00
|
|
|
OS << " 'overlay-relative': '" << (UseOverlayRelative ? "true" : "false")
|
|
|
|
<< "',\n";
|
Reapply [2] [VFS] Add 'overlay-relative' field to YAML files
This reapplies r261552 and r263748. Fixed testcase to reapply.
The VFS overlay mapping between virtual paths and real paths is done through
the 'external-contents' entries in YAML files, which contains hardcoded paths
to the real files.
When a module compilation crashes, headers are dumped into <name>.cache/vfs
directory and are mapped via the <name>.cache/vfs/vfs.yaml. The script
generated for reproduction uses -ivfsoverlay pointing to file to gather the
mapping between virtual paths and files inside <name>.cache/vfs. Currently, we
are only capable of reproducing such crashes in the same machine as they
happen, because of the hardcoded paths in 'external-contents'.
To be able to reproduce a crash in another machine, this patch introduces a new
option in the VFS yaml file called 'overlay-relative'. When it's equal to
'true' it means that the provided path to the YAML file through the
-ivfsoverlay option should also be used to prefix the final path for every
'external-contents'.
Example, given the invocation snippet "... -ivfsoverlay
<name>.cache/vfs/vfs.yaml" and the following entry in the yaml file:
"overlay-relative": "true",
"roots": [
...
"type": "directory",
"name": "/usr/include",
"contents": [
{
"type": "file",
"name": "stdio.h",
"external-contents": "/usr/include/stdio.h"
},
...
Here, a file manager request for virtual "/usr/include/stdio.h", that will map
into real path "/<absolute_path_to>/<name>.cache/vfs/usr/include/stdio.h.
This is a useful feature for debugging module crashes in machines other than
the one where the error happened.
Differential Revision: http://reviews.llvm.org/D17457
rdar://problem/24499339
llvm-svn: 263893
2016-03-20 02:08:48 +00:00
|
|
|
}
|
2014-05-20 21:43:27 +00:00
|
|
|
OS << " 'roots': [\n";
|
2014-05-21 22:46:51 +00:00
|
|
|
|
2014-07-15 01:24:35 +00:00
|
|
|
if (!Entries.empty()) {
|
|
|
|
const YAMLVFSEntry &Entry = Entries.front();
|
2020-05-12 14:42:22 -07:00
|
|
|
|
|
|
|
startDirectory(
|
|
|
|
Entry.IsDirectory ? Entry.VPath : path::parent_path(Entry.VPath)
|
|
|
|
);
|
Reapply [2] [VFS] Add 'overlay-relative' field to YAML files
This reapplies r261552 and r263748. Fixed testcase to reapply.
The VFS overlay mapping between virtual paths and real paths is done through
the 'external-contents' entries in YAML files, which contains hardcoded paths
to the real files.
When a module compilation crashes, headers are dumped into <name>.cache/vfs
directory and are mapped via the <name>.cache/vfs/vfs.yaml. The script
generated for reproduction uses -ivfsoverlay pointing to file to gather the
mapping between virtual paths and files inside <name>.cache/vfs. Currently, we
are only capable of reproducing such crashes in the same machine as they
happen, because of the hardcoded paths in 'external-contents'.
To be able to reproduce a crash in another machine, this patch introduces a new
option in the VFS yaml file called 'overlay-relative'. When it's equal to
'true' it means that the provided path to the YAML file through the
-ivfsoverlay option should also be used to prefix the final path for every
'external-contents'.
Example, given the invocation snippet "... -ivfsoverlay
<name>.cache/vfs/vfs.yaml" and the following entry in the yaml file:
"overlay-relative": "true",
"roots": [
...
"type": "directory",
"name": "/usr/include",
"contents": [
{
"type": "file",
"name": "stdio.h",
"external-contents": "/usr/include/stdio.h"
},
...
Here, a file manager request for virtual "/usr/include/stdio.h", that will map
into real path "/<absolute_path_to>/<name>.cache/vfs/usr/include/stdio.h.
This is a useful feature for debugging module crashes in machines other than
the one where the error happened.
Differential Revision: http://reviews.llvm.org/D17457
rdar://problem/24499339
llvm-svn: 263893
2016-03-20 02:08:48 +00:00
|
|
|
|
|
|
|
StringRef RPath = Entry.RPath;
|
|
|
|
if (UseOverlayRelative) {
|
2024-02-03 09:36:45 -08:00
|
|
|
assert(RPath.starts_with(OverlayDir) &&
|
Reapply [2] [VFS] Add 'overlay-relative' field to YAML files
This reapplies r261552 and r263748. Fixed testcase to reapply.
The VFS overlay mapping between virtual paths and real paths is done through
the 'external-contents' entries in YAML files, which contains hardcoded paths
to the real files.
When a module compilation crashes, headers are dumped into <name>.cache/vfs
directory and are mapped via the <name>.cache/vfs/vfs.yaml. The script
generated for reproduction uses -ivfsoverlay pointing to file to gather the
mapping between virtual paths and files inside <name>.cache/vfs. Currently, we
are only capable of reproducing such crashes in the same machine as they
happen, because of the hardcoded paths in 'external-contents'.
To be able to reproduce a crash in another machine, this patch introduces a new
option in the VFS yaml file called 'overlay-relative'. When it's equal to
'true' it means that the provided path to the YAML file through the
-ivfsoverlay option should also be used to prefix the final path for every
'external-contents'.
Example, given the invocation snippet "... -ivfsoverlay
<name>.cache/vfs/vfs.yaml" and the following entry in the yaml file:
"overlay-relative": "true",
"roots": [
...
"type": "directory",
"name": "/usr/include",
"contents": [
{
"type": "file",
"name": "stdio.h",
"external-contents": "/usr/include/stdio.h"
},
...
Here, a file manager request for virtual "/usr/include/stdio.h", that will map
into real path "/<absolute_path_to>/<name>.cache/vfs/usr/include/stdio.h.
This is a useful feature for debugging module crashes in machines other than
the one where the error happened.
Differential Revision: http://reviews.llvm.org/D17457
rdar://problem/24499339
llvm-svn: 263893
2016-03-20 02:08:48 +00:00
|
|
|
"Overlay dir must be contained in RPath");
|
2024-02-03 09:36:45 -08:00
|
|
|
RPath = RPath.slice(OverlayDir.size(), RPath.size());
|
Reapply [2] [VFS] Add 'overlay-relative' field to YAML files
This reapplies r261552 and r263748. Fixed testcase to reapply.
The VFS overlay mapping between virtual paths and real paths is done through
the 'external-contents' entries in YAML files, which contains hardcoded paths
to the real files.
When a module compilation crashes, headers are dumped into <name>.cache/vfs
directory and are mapped via the <name>.cache/vfs/vfs.yaml. The script
generated for reproduction uses -ivfsoverlay pointing to file to gather the
mapping between virtual paths and files inside <name>.cache/vfs. Currently, we
are only capable of reproducing such crashes in the same machine as they
happen, because of the hardcoded paths in 'external-contents'.
To be able to reproduce a crash in another machine, this patch introduces a new
option in the VFS yaml file called 'overlay-relative'. When it's equal to
'true' it means that the provided path to the YAML file through the
-ivfsoverlay option should also be used to prefix the final path for every
'external-contents'.
Example, given the invocation snippet "... -ivfsoverlay
<name>.cache/vfs/vfs.yaml" and the following entry in the yaml file:
"overlay-relative": "true",
"roots": [
...
"type": "directory",
"name": "/usr/include",
"contents": [
{
"type": "file",
"name": "stdio.h",
"external-contents": "/usr/include/stdio.h"
},
...
Here, a file manager request for virtual "/usr/include/stdio.h", that will map
into real path "/<absolute_path_to>/<name>.cache/vfs/usr/include/stdio.h.
This is a useful feature for debugging module crashes in machines other than
the one where the error happened.
Differential Revision: http://reviews.llvm.org/D17457
rdar://problem/24499339
llvm-svn: 263893
2016-03-20 02:08:48 +00:00
|
|
|
}
|
|
|
|
|
2020-05-12 14:42:22 -07:00
|
|
|
bool IsCurrentDirEmpty = true;
|
|
|
|
if (!Entry.IsDirectory) {
|
2020-03-27 15:02:24 -07:00
|
|
|
writeEntry(path::filename(Entry.VPath), RPath);
|
2020-05-12 14:42:22 -07:00
|
|
|
IsCurrentDirEmpty = false;
|
|
|
|
}
|
2014-07-15 01:24:35 +00:00
|
|
|
|
|
|
|
for (const auto &Entry : Entries.slice(1)) {
|
2020-03-27 15:02:24 -07:00
|
|
|
StringRef Dir =
|
|
|
|
Entry.IsDirectory ? Entry.VPath : path::parent_path(Entry.VPath);
|
|
|
|
if (Dir == DirStack.back()) {
|
2020-05-12 14:42:22 -07:00
|
|
|
if (!IsCurrentDirEmpty) {
|
2020-03-27 15:02:24 -07:00
|
|
|
OS << ",\n";
|
|
|
|
}
|
|
|
|
} else {
|
2020-05-12 14:42:22 -07:00
|
|
|
bool IsDirPoppedFromStack = false;
|
2014-07-15 01:24:35 +00:00
|
|
|
while (!DirStack.empty() && !containedIn(DirStack.back(), Dir)) {
|
|
|
|
OS << "\n";
|
|
|
|
endDirectory();
|
2020-05-12 14:42:22 -07:00
|
|
|
IsDirPoppedFromStack = true;
|
|
|
|
}
|
|
|
|
if (IsDirPoppedFromStack || !IsCurrentDirEmpty) {
|
|
|
|
OS << ",\n";
|
2014-07-15 01:24:35 +00:00
|
|
|
}
|
|
|
|
startDirectory(Dir);
|
2020-05-12 14:42:22 -07:00
|
|
|
IsCurrentDirEmpty = true;
|
2014-05-21 22:46:51 +00:00
|
|
|
}
|
Reapply [2] [VFS] Add 'overlay-relative' field to YAML files
This reapplies r261552 and r263748. Fixed testcase to reapply.
The VFS overlay mapping between virtual paths and real paths is done through
the 'external-contents' entries in YAML files, which contains hardcoded paths
to the real files.
When a module compilation crashes, headers are dumped into <name>.cache/vfs
directory and are mapped via the <name>.cache/vfs/vfs.yaml. The script
generated for reproduction uses -ivfsoverlay pointing to file to gather the
mapping between virtual paths and files inside <name>.cache/vfs. Currently, we
are only capable of reproducing such crashes in the same machine as they
happen, because of the hardcoded paths in 'external-contents'.
To be able to reproduce a crash in another machine, this patch introduces a new
option in the VFS yaml file called 'overlay-relative'. When it's equal to
'true' it means that the provided path to the YAML file through the
-ivfsoverlay option should also be used to prefix the final path for every
'external-contents'.
Example, given the invocation snippet "... -ivfsoverlay
<name>.cache/vfs/vfs.yaml" and the following entry in the yaml file:
"overlay-relative": "true",
"roots": [
...
"type": "directory",
"name": "/usr/include",
"contents": [
{
"type": "file",
"name": "stdio.h",
"external-contents": "/usr/include/stdio.h"
},
...
Here, a file manager request for virtual "/usr/include/stdio.h", that will map
into real path "/<absolute_path_to>/<name>.cache/vfs/usr/include/stdio.h.
This is a useful feature for debugging module crashes in machines other than
the one where the error happened.
Differential Revision: http://reviews.llvm.org/D17457
rdar://problem/24499339
llvm-svn: 263893
2016-03-20 02:08:48 +00:00
|
|
|
StringRef RPath = Entry.RPath;
|
|
|
|
if (UseOverlayRelative) {
|
2024-02-03 09:36:45 -08:00
|
|
|
assert(RPath.starts_with(OverlayDir) &&
|
Reapply [2] [VFS] Add 'overlay-relative' field to YAML files
This reapplies r261552 and r263748. Fixed testcase to reapply.
The VFS overlay mapping between virtual paths and real paths is done through
the 'external-contents' entries in YAML files, which contains hardcoded paths
to the real files.
When a module compilation crashes, headers are dumped into <name>.cache/vfs
directory and are mapped via the <name>.cache/vfs/vfs.yaml. The script
generated for reproduction uses -ivfsoverlay pointing to file to gather the
mapping between virtual paths and files inside <name>.cache/vfs. Currently, we
are only capable of reproducing such crashes in the same machine as they
happen, because of the hardcoded paths in 'external-contents'.
To be able to reproduce a crash in another machine, this patch introduces a new
option in the VFS yaml file called 'overlay-relative'. When it's equal to
'true' it means that the provided path to the YAML file through the
-ivfsoverlay option should also be used to prefix the final path for every
'external-contents'.
Example, given the invocation snippet "... -ivfsoverlay
<name>.cache/vfs/vfs.yaml" and the following entry in the yaml file:
"overlay-relative": "true",
"roots": [
...
"type": "directory",
"name": "/usr/include",
"contents": [
{
"type": "file",
"name": "stdio.h",
"external-contents": "/usr/include/stdio.h"
},
...
Here, a file manager request for virtual "/usr/include/stdio.h", that will map
into real path "/<absolute_path_to>/<name>.cache/vfs/usr/include/stdio.h.
This is a useful feature for debugging module crashes in machines other than
the one where the error happened.
Differential Revision: http://reviews.llvm.org/D17457
rdar://problem/24499339
llvm-svn: 263893
2016-03-20 02:08:48 +00:00
|
|
|
"Overlay dir must be contained in RPath");
|
2024-02-03 09:36:45 -08:00
|
|
|
RPath = RPath.slice(OverlayDir.size(), RPath.size());
|
Reapply [2] [VFS] Add 'overlay-relative' field to YAML files
This reapplies r261552 and r263748. Fixed testcase to reapply.
The VFS overlay mapping between virtual paths and real paths is done through
the 'external-contents' entries in YAML files, which contains hardcoded paths
to the real files.
When a module compilation crashes, headers are dumped into <name>.cache/vfs
directory and are mapped via the <name>.cache/vfs/vfs.yaml. The script
generated for reproduction uses -ivfsoverlay pointing to file to gather the
mapping between virtual paths and files inside <name>.cache/vfs. Currently, we
are only capable of reproducing such crashes in the same machine as they
happen, because of the hardcoded paths in 'external-contents'.
To be able to reproduce a crash in another machine, this patch introduces a new
option in the VFS yaml file called 'overlay-relative'. When it's equal to
'true' it means that the provided path to the YAML file through the
-ivfsoverlay option should also be used to prefix the final path for every
'external-contents'.
Example, given the invocation snippet "... -ivfsoverlay
<name>.cache/vfs/vfs.yaml" and the following entry in the yaml file:
"overlay-relative": "true",
"roots": [
...
"type": "directory",
"name": "/usr/include",
"contents": [
{
"type": "file",
"name": "stdio.h",
"external-contents": "/usr/include/stdio.h"
},
...
Here, a file manager request for virtual "/usr/include/stdio.h", that will map
into real path "/<absolute_path_to>/<name>.cache/vfs/usr/include/stdio.h.
This is a useful feature for debugging module crashes in machines other than
the one where the error happened.
Differential Revision: http://reviews.llvm.org/D17457
rdar://problem/24499339
llvm-svn: 263893
2016-03-20 02:08:48 +00:00
|
|
|
}
|
2020-05-12 14:42:22 -07:00
|
|
|
if (!Entry.IsDirectory) {
|
2020-05-05 23:45:49 -07:00
|
|
|
writeEntry(path::filename(Entry.VPath), RPath);
|
2020-05-12 14:42:22 -07:00
|
|
|
IsCurrentDirEmpty = false;
|
|
|
|
}
|
2014-05-21 22:46:51 +00:00
|
|
|
}
|
|
|
|
|
2014-07-15 01:24:35 +00:00
|
|
|
while (!DirStack.empty()) {
|
|
|
|
OS << "\n";
|
|
|
|
endDirectory();
|
|
|
|
}
|
2014-05-21 22:46:51 +00:00
|
|
|
OS << "\n";
|
|
|
|
}
|
|
|
|
|
2014-07-15 01:24:35 +00:00
|
|
|
OS << " ]\n"
|
2014-05-20 21:43:27 +00:00
|
|
|
<< "}\n";
|
|
|
|
}
|
2014-05-21 22:46:51 +00:00
|
|
|
|
|
|
|
void YAMLVFSWriter::write(llvm::raw_ostream &OS) {
|
2018-09-26 22:16:28 +00:00
|
|
|
llvm::sort(Mappings, [](const YAMLVFSEntry &LHS, const YAMLVFSEntry &RHS) {
|
2014-05-21 22:46:51 +00:00
|
|
|
return LHS.VPath < RHS.VPath;
|
|
|
|
});
|
|
|
|
|
2016-04-13 19:28:21 +00:00
|
|
|
JSONWriter(OS).write(Mappings, UseExternalNames, IsCaseSensitive,
|
2018-10-24 22:40:54 +00:00
|
|
|
IsOverlayRelative, OverlayDir);
|
2014-05-21 22:46:51 +00:00
|
|
|
}
|
2014-06-24 19:37:16 +00:00
|
|
|
|
2018-10-10 13:27:25 +00:00
|
|
|
vfs::recursive_directory_iterator::recursive_directory_iterator(
|
|
|
|
FileSystem &FS_, const Twine &Path, std::error_code &EC)
|
2014-06-25 20:25:40 +00:00
|
|
|
: FS(&FS_) {
|
|
|
|
directory_iterator I = FS->dir_begin(Path, EC);
|
2017-03-14 00:14:40 +00:00
|
|
|
if (I != directory_iterator()) {
|
2018-10-31 23:36:10 +00:00
|
|
|
State = std::make_shared<detail::RecDirIterState>();
|
2024-06-21 14:59:05 +02:00
|
|
|
State->Stack.push_back(I);
|
2014-06-25 20:25:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
vfs::recursive_directory_iterator &
|
|
|
|
recursive_directory_iterator::increment(std::error_code &EC) {
|
2018-10-31 23:36:10 +00:00
|
|
|
assert(FS && State && !State->Stack.empty() && "incrementing past end");
|
2024-06-21 14:59:05 +02:00
|
|
|
assert(!State->Stack.back()->path().empty() && "non-canonical end iterator");
|
2014-06-25 20:25:40 +00:00
|
|
|
vfs::directory_iterator End;
|
2018-10-31 23:36:10 +00:00
|
|
|
|
|
|
|
if (State->HasNoPushRequest)
|
|
|
|
State->HasNoPushRequest = false;
|
|
|
|
else {
|
2024-06-21 14:59:05 +02:00
|
|
|
if (State->Stack.back()->type() == sys::fs::file_type::directory_file) {
|
|
|
|
vfs::directory_iterator I =
|
|
|
|
FS->dir_begin(State->Stack.back()->path(), EC);
|
2018-10-31 23:36:10 +00:00
|
|
|
if (I != End) {
|
2024-06-21 14:59:05 +02:00
|
|
|
State->Stack.push_back(I);
|
2018-10-31 23:36:10 +00:00
|
|
|
return *this;
|
|
|
|
}
|
2014-06-25 20:25:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-21 14:59:05 +02:00
|
|
|
while (!State->Stack.empty() && State->Stack.back().increment(EC) == End)
|
|
|
|
State->Stack.pop_back();
|
2014-06-25 20:25:40 +00:00
|
|
|
|
2018-10-31 23:36:10 +00:00
|
|
|
if (State->Stack.empty())
|
2014-06-25 20:25:40 +00:00
|
|
|
State.reset(); // end iterator
|
|
|
|
|
|
|
|
return *this;
|
2014-07-06 17:43:24 +00:00
|
|
|
}
|
2024-01-30 15:39:18 -08:00
|
|
|
|
|
|
|
const char FileSystem::ID = 0;
|
|
|
|
const char OverlayFileSystem::ID = 0;
|
|
|
|
const char ProxyFileSystem::ID = 0;
|
|
|
|
const char InMemoryFileSystem::ID = 0;
|
|
|
|
const char RedirectingFileSystem::ID = 0;
|