src/archive.h
browsing at commit = 9881d02ac31dadb3794f4728eb6cef4afe5721d3
#pragma once
#include <cstdint>
#include <cstdio>
#include <ctime>
#include <stdexcept>
#include <string>
// Thrown for any tar/gzip writing failure.
class ArchiveError : public std::runtime_error {
public:
explicit ArchiveError(const std::string &what) : std::runtime_error(what) {}
};
// Streams a gzip-compressed tar archive to a file. Entry paths longer than the
// ustar limit are emitted via the GNU long-name extension, which modern tar
// implementations understand. Not thread safe: use one writer per archive.
class TarGzWriter {
public:
explicit TarGzWriter(const std::string &path);
~TarGzWriter();
TarGzWriter(const TarGzWriter &) = delete;
TarGzWriter &operator=(const TarGzWriter &) = delete;
void add_file(const std::string &path, uint32_t mode, std::time_t mtime,
const char *data, uint64_t size);
void add_symlink(const std::string &path, const std::string &target,
std::time_t mtime);
void add_dir(const std::string &path, std::time_t mtime);
// Writes the terminating zero blocks and flushes the gzip stream. Must be
// called for the archive to be valid; the destructor does not call it so a
// half-built archive is never silently completed.
void finish();
private:
void write_header(const std::string &path, uint32_t mode, std::time_t mtime,
uint64_t size, char typeflag, const std::string &linkname);
void write_gnu_long(const std::string &value, char typeflag);
void write_padding(uint64_t size); // pads body to a 512-byte boundary
void deflate_chunk(const void *data, size_t size, int flush);
FILE *file_ = nullptr;
void *stream_ = nullptr; // z_stream*, type-erased to keep zlib out of the header
bool finished_ = false;
};