forked from OSchip/llvm-project
122 lines
3.9 KiB
C++
122 lines
3.9 KiB
C++
//===- Reproduce.cpp - Utilities for creating reproducers -----------------===//
|
|
//
|
|
// The LLVM Linker
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "lld/Core/Reproduce.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/ADT/Twine.h"
|
|
#include "llvm/Option/Arg.h"
|
|
#include "llvm/Support/Error.h"
|
|
#include "llvm/Support/FileSystem.h"
|
|
#include "llvm/Support/Format.h"
|
|
#include "llvm/Support/Path.h"
|
|
|
|
using namespace lld;
|
|
using namespace llvm;
|
|
using namespace sys;
|
|
|
|
CpioFile::CpioFile(std::unique_ptr<raw_fd_ostream> OS, StringRef S)
|
|
: OS(std::move(OS)), Basename(S) {}
|
|
|
|
ErrorOr<CpioFile *> CpioFile::create(StringRef OutputPath) {
|
|
std::string Path = (OutputPath + ".cpio").str();
|
|
std::error_code EC;
|
|
auto OS = llvm::make_unique<raw_fd_ostream>(Path, EC, sys::fs::F_None);
|
|
if (EC)
|
|
return EC;
|
|
return new CpioFile(std::move(OS), path::filename(OutputPath));
|
|
}
|
|
|
|
static void writeMember(raw_fd_ostream &OS, StringRef Path, StringRef Data) {
|
|
// The c_dev/c_ino pair should be unique according to the spec,
|
|
// but no one seems to care.
|
|
OS << "070707"; // c_magic
|
|
OS << "000000"; // c_dev
|
|
OS << "000000"; // c_ino
|
|
OS << "100664"; // c_mode: C_ISREG | rw-rw-r--
|
|
OS << "000000"; // c_uid
|
|
OS << "000000"; // c_gid
|
|
OS << "000001"; // c_nlink
|
|
OS << "000000"; // c_rdev
|
|
OS << "00000000000"; // c_mtime
|
|
OS << format("%06o", Path.size() + 1); // c_namesize
|
|
OS << format("%011o", Data.size()); // c_filesize
|
|
OS << Path << '\0'; // c_name
|
|
OS << Data; // c_filedata
|
|
}
|
|
|
|
void CpioFile::append(StringRef Path, StringRef Data) {
|
|
if (!Seen.insert(Path).second)
|
|
return;
|
|
|
|
// Construct an in-archive filename so that /home/foo/bar is stored
|
|
// as baz/home/foo/bar where baz is the basename of the output file.
|
|
// (i.e. in that case we are creating baz.cpio.)
|
|
SmallString<128> Fullpath;
|
|
path::append(Fullpath, Basename, Path);
|
|
|
|
// Use unix path separators so the cpio can be extracted on both unix and
|
|
// windows.
|
|
std::replace(Fullpath.begin(), Fullpath.end(), '\\', '/');
|
|
|
|
writeMember(*OS, Fullpath, Data);
|
|
|
|
// Print the trailer and seek back.
|
|
// This way we have a valid archive if we crash.
|
|
uint64_t Pos = OS->tell();
|
|
writeMember(*OS, "TRAILER!!!", "");
|
|
OS->seek(Pos);
|
|
}
|
|
|
|
// Makes a given pathname an absolute path first, and then remove
|
|
// beginning /. For example, "../foo.o" is converted to "home/john/foo.o",
|
|
// assuming that the current directory is "/home/john/bar".
|
|
std::string lld::relativeToRoot(StringRef Path) {
|
|
SmallString<128> Abs = Path;
|
|
if (sys::fs::make_absolute(Abs))
|
|
return Path;
|
|
path::remove_dots(Abs, /*remove_dot_dot=*/true);
|
|
|
|
// This is Windows specific. root_name() returns a drive letter
|
|
// (e.g. "c:") or a UNC name (//net). We want to keep it as part
|
|
// of the result.
|
|
SmallString<128> Res;
|
|
StringRef Root = path::root_name(Abs);
|
|
if (Root.endswith(":"))
|
|
Res = Root.drop_back();
|
|
else if (Root.startswith("//"))
|
|
Res = Root.substr(2);
|
|
|
|
path::append(Res, path::relative_path(Abs));
|
|
|
|
return Res.str();
|
|
}
|
|
|
|
// Quote a given string if it contains a space character.
|
|
std::string lld::quote(StringRef S) {
|
|
if (S.find(' ') == StringRef::npos)
|
|
return S;
|
|
return ("\"" + S + "\"").str();
|
|
}
|
|
|
|
std::string lld::rewritePath(StringRef S) {
|
|
if (fs::exists(S))
|
|
return relativeToRoot(S);
|
|
return S;
|
|
}
|
|
|
|
std::string lld::stringize(opt::Arg *Arg) {
|
|
std::string K = Arg->getSpelling();
|
|
if (Arg->getNumValues() == 0)
|
|
return K;
|
|
std::string V = quote(Arg->getValue());
|
|
if (Arg->getOption().getRenderStyle() == opt::Option::RenderJoinedStyle)
|
|
return K + V;
|
|
return K + " " + V;
|
|
}
|