1 //===- Reproduce.cpp - Utilities for creating reproducers -----------------===//
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "lld/Core/Reproduce.h"
11 #include "llvm/ADT/STLExtras.h"
12 #include "llvm/ADT/Twine.h"
13 #include "llvm/Option/Arg.h"
14 #include "llvm/Support/Error.h"
15 #include "llvm/Support/FileSystem.h"
16 #include "llvm/Support/Format.h"
17 #include "llvm/Support/Path.h"
23 CpioFile::CpioFile(std::unique_ptr<raw_fd_ostream> OS, StringRef S)
24 : OS(std::move(OS)), Basename(S) {}
26 ErrorOr<CpioFile *> CpioFile::create(StringRef OutputPath) {
27 std::string Path = (OutputPath + ".cpio").str();
29 auto OS = llvm::make_unique<raw_fd_ostream>(Path, EC, sys::fs::F_None);
32 return new CpioFile(std::move(OS), path::filename(OutputPath));
35 static void writeMember(raw_fd_ostream &OS, StringRef Path, StringRef Data) {
36 // The c_dev/c_ino pair should be unique according to the spec,
37 // but no one seems to care.
38 OS << "070707"; // c_magic
39 OS << "000000"; // c_dev
40 OS << "000000"; // c_ino
41 OS << "100664"; // c_mode: C_ISREG | rw-rw-r--
42 OS << "000000"; // c_uid
43 OS << "000000"; // c_gid
44 OS << "000001"; // c_nlink
45 OS << "000000"; // c_rdev
46 OS << "00000000000"; // c_mtime
47 OS << format("%06o", Path.size() + 1); // c_namesize
48 OS << format("%011o", Data.size()); // c_filesize
49 OS << Path << '\0'; // c_name
50 OS << Data; // c_filedata
53 void CpioFile::append(StringRef Path, StringRef Data) {
54 if (!Seen.insert(Path).second)
57 // Construct an in-archive filename so that /home/foo/bar is stored
58 // as baz/home/foo/bar where baz is the basename of the output file.
59 // (i.e. in that case we are creating baz.cpio.)
60 SmallString<128> Fullpath;
61 path::append(Fullpath, Basename, Path);
63 writeMember(*OS, convertToUnixPathSeparator(Fullpath), Data);
65 // Print the trailer and seek back.
66 // This way we have a valid archive if we crash.
67 uint64_t Pos = OS->tell();
68 writeMember(*OS, "TRAILER!!!", "");
72 // Makes a given pathname an absolute path first, and then remove
73 // beginning /. For example, "../foo.o" is converted to "home/john/foo.o",
74 // assuming that the current directory is "/home/john/bar".
75 // Returned string is a forward slash separated path even on Windows to avoid
76 // a mess with backslash-as-escape and backslash-as-path-separator.
77 std::string lld::relativeToRoot(StringRef Path) {
78 SmallString<128> Abs = Path;
79 if (sys::fs::make_absolute(Abs))
81 path::remove_dots(Abs, /*remove_dot_dot=*/true);
83 // This is Windows specific. root_name() returns a drive letter
84 // (e.g. "c:") or a UNC name (//net). We want to keep it as part
87 StringRef Root = path::root_name(Abs);
88 if (Root.endswith(":"))
89 Res = Root.drop_back();
90 else if (Root.startswith("//"))
93 path::append(Res, path::relative_path(Abs));
94 return convertToUnixPathSeparator(Res);
97 // Quote a given string if it contains a space character.
98 std::string lld::quote(StringRef S) {
99 if (S.find(' ') == StringRef::npos)
101 return ("\"" + S + "\"").str();
104 std::string lld::rewritePath(StringRef S) {
106 return relativeToRoot(S);
110 std::string lld::stringize(opt::Arg *Arg) {
111 std::string K = Arg->getSpelling();
112 if (Arg->getNumValues() == 0)
114 std::string V = quote(Arg->getValue());
115 if (Arg->getOption().getRenderStyle() == opt::Option::RenderJoinedStyle)
120 std::string lld::convertToUnixPathSeparator(StringRef S) {
122 std::string Ret = S.str();
123 std::replace(Ret.begin(), Ret.end(), '\\', '/');