1
1
mirror of https://github.com/rui314/mold.git synced 2024-09-21 18:08:01 +03:00
mold/tar.cc

104 lines
2.7 KiB
C++
Raw Normal View History

2021-04-08 18:29:01 +03:00
#include "mold.h"
namespace mold {
2021-04-08 18:29:01 +03:00
// A tar file consists of one or more Ustar header followed by data.
// Each Ustar header represents a single file in an archive.
//
// tar is an old file format, and its `name` field is only 100 bytes long.
2021-04-08 19:38:25 +03:00
// If `name` is longer than 100 bytes, we can emit a PAX header before a
// Ustar header to store a long filename.
2021-04-08 18:29:01 +03:00
//
2021-04-08 19:38:25 +03:00
// For simplicity, we always emit a PAX header even for a short filename.
2021-04-08 18:29:01 +03:00
struct UstarHeader {
2021-05-02 13:21:24 +03:00
void flush() {
2021-04-08 18:29:01 +03:00
memset(checksum, ' ', sizeof(checksum));
memcpy(magic, "ustar", 5);
memcpy(version, "00", 2);
2021-05-02 13:21:24 +03:00
// Compute checksum
2021-04-08 18:29:01 +03:00
int sum = 0;
for (i64 i = 0; i < sizeof(*this); i++)
sum += ((u8 *)this)[i];
sprintf(checksum, "%06o", sum);
}
char name[100];
char mode[8];
char uid[8];
char gid[8];
char size[12];
char mtime[12];
char checksum[8];
char typeflag[1];
char linkname[100];
char magic[6];
char version[2];
char uname[32];
char gname[32];
char devmajor[8];
char devminor[8];
char prefix[155];
char pad[12];
};
2021-09-27 11:37:23 +03:00
std::string TarFile::encode_path(std::string path) {
path = path_clean(basedir + "/" + path);
2021-04-08 19:59:13 +03:00
2021-04-08 19:38:25 +03:00
// Construct a string which contains something like
// "16 path=foo/bar\n" where 16 is the size of the string
// including the size string itself.
i64 len = std::string(" path=\n").size() + path.size();
2021-04-08 18:29:01 +03:00
i64 total = std::to_string(len).size() + len;
total = std::to_string(total).size() + len;
2021-05-02 13:21:24 +03:00
return std::to_string(total) + " path=" + path + "\n";
}
2021-04-08 18:29:01 +03:00
2021-05-02 13:21:24 +03:00
void TarFile::append(std::string path, std::string_view data) {
contents.push_back({path, data});
2021-04-08 18:29:01 +03:00
2021-05-02 13:21:24 +03:00
size_ += BLOCK_SIZE * 2;
2021-09-27 11:37:23 +03:00
size_ += align_to(encode_path(path).size(), BLOCK_SIZE);
2021-05-02 13:21:24 +03:00
size_ += align_to(data.size(), BLOCK_SIZE);
2021-04-08 18:29:01 +03:00
}
void TarFile::write_to(u8 *buf) {
2021-05-02 13:21:24 +03:00
u8 *start = buf;
memset(buf, 0, size_);
2021-04-08 18:29:01 +03:00
2021-05-02 13:21:24 +03:00
for (i64 i = 0; i < contents.size(); i++) {
assert(buf - start <= size_);
2021-04-09 11:39:17 +03:00
2021-05-02 13:21:24 +03:00
const std::string &path = contents[i].first;
std::string_view data = contents[i].second;
2021-04-08 18:29:01 +03:00
2021-05-02 13:21:24 +03:00
// Write PAX header
2021-09-27 11:37:23 +03:00
static_assert(sizeof(UstarHeader) == BLOCK_SIZE);
2021-05-02 13:21:24 +03:00
UstarHeader &pax = *(UstarHeader *)buf;
buf += BLOCK_SIZE;
2021-09-27 11:37:23 +03:00
std::string attr = encode_path(path);
2021-05-02 13:21:24 +03:00
sprintf(pax.size, "%011zo", attr.size());
pax.typeflag[0] = 'x';
pax.flush();
// Write pathname
memcpy(buf, attr.data(), attr.size());
buf += align_to(attr.size(), BLOCK_SIZE);
2021-04-08 18:29:01 +03:00
2021-05-02 13:21:24 +03:00
// Write Ustar header
UstarHeader &ustar = *(UstarHeader *)buf;
buf += BLOCK_SIZE;
2021-04-08 19:59:13 +03:00
2021-05-02 13:21:24 +03:00
memcpy(ustar.mode, "0000664", 8);
sprintf(ustar.size, "%011zo", data.size());
ustar.flush();
// Write file contents
memcpy(buf, data.data(), data.size());
buf += align_to(data.size(), BLOCK_SIZE);
}
}
} // namespace mold