#include "CacheEntryReader.hpp"
-#include "Checksum.hpp"
#include "Compressor.hpp"
#include "Error.hpp"
#include "ccache.hpp"
CacheEntryReader::CacheEntryReader(FILE* stream,
const uint8_t expected_magic[4],
- uint8_t expected_version,
- Checksum* checksum)
- : m_checksum(checksum)
+ uint8_t expected_version)
{
uint8_t header_bytes[15];
if (fread(header_bytes, sizeof(header_bytes), 1, stream) != 1) {
}
}
- if (m_checksum) {
- m_checksum->update(header_bytes, sizeof(header_bytes));
- }
-
+ m_checksum.update(header_bytes, sizeof(header_bytes));
m_decompressor = Decompressor::create_from_type(m_compression_type, stream);
}
CacheEntryReader::read(void* data, size_t count)
{
m_decompressor->read(data, count);
- m_checksum->update(data, count);
+ m_checksum.update(data, count);
}
void
CacheEntryReader::finalize()
{
+ uint64_t actual_digest = m_checksum.digest();
+
+ uint8_t buffer[8];
+ read(buffer, sizeof(buffer));
+ uint64_t expected_digest;
+ Util::big_endian_to_int(buffer, expected_digest);
+
+ if (actual_digest != expected_digest) {
+ throw Error(
+ fmt::format("Incorrect checksum (actual 0x{:016x}, expected 0x{:016x})",
+ actual_digest,
+ expected_digest));
+ }
+
m_decompressor->finalize();
}
#pragma once
+#include "Checksum.hpp"
#include "Decompressor.hpp"
#include "Util.hpp"
#include <cstdio>
#include <memory>
-class Checksum;
-
// This class knows how to read a cache entry with a common header and a
// payload part that is different depending on the cache entry type (result or
// manifest).
// - stream: Stream to read header and payload from.
// - expected_magic: Expected magic bytes (first four bytes of the file).
// - expected_version: Expected file format version.
- // - checksum: Checksum state that will be updated with the read bytes, or
// nullptr for no checksumming.
CacheEntryReader(FILE* stream,
const uint8_t expected_magic[4],
- uint8_t expected_version,
- Checksum* checksum = nullptr);
+ uint8_t expected_version);
// Dump header information in text format.
//
// entry and throws Error if any integrity issues are found.
void finalize();
- // Get size of the content (header + payload).
+ // Get size of the payload,
+ uint64_t payload_size() const;
+
+ // Get size of the content (header + payload + checksum).
uint64_t content_size() const;
private:
std::unique_ptr<Decompressor> m_decompressor;
- Checksum* m_checksum;
+ Checksum m_checksum;
char m_magic[4];
uint8_t m_version;
Compression::Type m_compression_type;
Util::big_endian_to_int(buffer, value);
}
+inline uint64_t
+CacheEntryReader::payload_size() const
+{
+ return m_content_size - 15 - 8;
+}
+
inline uint64_t
CacheEntryReader::content_size() const
{
#include "CacheEntryWriter.hpp"
-#include "Checksum.hpp"
-
CacheEntryWriter::CacheEntryWriter(FILE* stream,
const uint8_t magic[4],
uint8_t version,
Compression::Type compression_type,
int8_t compression_level,
- uint64_t content_size,
- Checksum& checksum)
+ uint64_t payload_size)
: m_compressor(
- Compressor::create_from_type(compression_type, stream, compression_level)),
- m_checksum(checksum)
+ Compressor::create_from_type(compression_type, stream, compression_level))
{
uint8_t header_bytes[15];
memcpy(header_bytes, magic, 4);
header_bytes[4] = version;
header_bytes[5] = static_cast<uint8_t>(compression_type);
header_bytes[6] = m_compressor->actual_compression_level();
+ uint64_t content_size = 15 + payload_size + 8;
Util::int_to_big_endian(content_size, header_bytes + 7);
if (fwrite(header_bytes, sizeof(header_bytes), 1, stream) != 1) {
throw Error("Failed to write cache entry header");
}
- checksum.update(header_bytes, sizeof(header_bytes));
+ m_checksum.update(header_bytes, sizeof(header_bytes));
}
void
void
CacheEntryWriter::finalize()
{
+ uint8_t buffer[8];
+ Util::int_to_big_endian(m_checksum.digest(), buffer);
+ m_compressor->write(buffer, sizeof(buffer));
m_compressor->finalize();
}
#pragma once
+#include "Checksum.hpp"
#include "Compressor.hpp"
#include "Util.hpp"
#include <cstdio>
#include <memory>
-class Checksum;
-
// This class knows how to write a cache entry with a common header and a
// payload part that is different depending on the cache entry type (result or
// manifest).
// - version: File format version.
// - compression_type: Compression type to use.
// - compression_level: Compression level to use.
- // - content_size: Content size.
- // - checksum: Checksum state that will be updated with the written bytes.
+ // - payload_size: Payload size.
CacheEntryWriter(FILE* stream,
const uint8_t magic[4],
uint8_t version,
Compression::Type compression_type,
int8_t compression_level,
- uint64_t content_size,
- Checksum& checksum);
+ uint64_t payload_size);
// Write data to the payload from a buffer.
//
private:
std::unique_ptr<Compressor> m_compressor;
- Checksum& m_checksum;
+ Checksum m_checksum;
};
template<typename T>
return {};
}
- Checksum checksum;
- CacheEntryReader reader(
- file.get(), k_manifest_magic, k_manifest_version, &checksum);
+ CacheEntryReader reader(file.get(), k_manifest_magic, k_manifest_version);
if (dump_stream) {
reader.dump_header(dump_stream);
reader.read(entry.name.bytes, DIGEST_SIZE);
}
- uint64_t actual_checksum = checksum.digest();
- uint64_t expected_checksum;
- reader.read(expected_checksum);
- if (actual_checksum != expected_checksum) {
- throw Error(
- fmt::format("Incorrect checksum (actual 0x{:016x}, expected 0x{:016x})",
- actual_checksum,
- expected_checksum));
- }
-
reader.finalize();
return mf;
}
static bool
write_manifest(const std::string& path, const ManifestData& mf)
{
- uint64_t content_size = 15;
- content_size += 4; // n_files
+ uint64_t payload_size = 0;
+ payload_size += 4; // n_files
for (size_t i = 0; i < mf.files.size(); ++i) {
- content_size += 2 + mf.files[i].length();
+ payload_size += 2 + mf.files[i].length();
}
- content_size += 4; // n_file_infos
- content_size += mf.file_infos.size() * (4 + DIGEST_SIZE + 8 + 8 + 8);
- content_size += 4; // n_results
+ payload_size += 4; // n_file_infos
+ payload_size += mf.file_infos.size() * (4 + DIGEST_SIZE + 8 + 8 + 8);
+ payload_size += 4; // n_results
for (size_t i = 0; i < mf.results.size(); ++i) {
- content_size += 4; // n_file_info_indexes
- content_size += mf.results[i].file_info_indexes.size() * 4;
- content_size += DIGEST_SIZE;
+ payload_size += 4; // n_file_info_indexes
+ payload_size += mf.results[i].file_info_indexes.size() * 4;
+ payload_size += DIGEST_SIZE;
}
- content_size += 8; // checksum
- Checksum checksum;
AtomicFile atomic_manifest_file(path, AtomicFile::Mode::binary);
CacheEntryWriter writer(atomic_manifest_file.stream(),
k_manifest_magic,
k_manifest_version,
Compression::type_from_config(),
Compression::level_from_config(),
- content_size,
- checksum);
+ payload_size);
writer.write<uint32_t>(mf.files.size());
for (uint32_t i = 0; i < mf.files.size(); ++i) {
writer.write<uint16_t>(mf.files[i].length());
writer.write(mf.results[i].name.bytes, DIGEST_SIZE);
}
- writer.write(checksum.digest());
writer.finalize();
atomic_manifest_file.commit();
return true;
#include "AtomicFile.hpp"
#include "CacheEntryReader.hpp"
#include "CacheEntryWriter.hpp"
-#include "Checksum.hpp"
#include "Config.hpp"
#include "Error.hpp"
#include "File.hpp"
return false;
}
- Checksum checksum;
- CacheEntryReader reader(
- file.get(), k_result_magic, k_result_version, &checksum);
+ CacheEntryReader reader(file.get(), k_result_magic, k_result_version);
if (dump_stream) {
reader.dump_header(dump_stream);
fmt::format("Too few entries (read {}, expected {})", i, n_entries));
}
- uint64_t actual_checksum = checksum.digest();
- uint64_t expected_checksum;
- reader.read(expected_checksum);
- if (actual_checksum != expected_checksum) {
- throw Error(
- fmt::format("Incorrect checksum (actual 0x{:016x}, expected 0x{:016x})",
- actual_checksum,
- expected_checksum));
- }
-
reader.finalize();
return true;
}
static void
write_result(const std::string& path, const ResultFileMap& result_file_map)
{
- uint64_t content_size = 15;
- content_size += 1; // n_entries
+ uint64_t payload_size = 0;
+ payload_size += 1; // n_entries
for (const auto& pair : result_file_map) {
const auto& suffix = pair.first;
const auto& result_file = pair.second;
throw Error(
fmt::format("Failed to stat {}: {}", result_file, strerror(errno)));
}
- content_size += 1; // embedded_file_marker
- content_size += 1; // suffix_len
- content_size += suffix.length(); // suffix
- content_size += 8; // data_len
- content_size += source_file_size; // data
+ payload_size += 1; // embedded_file_marker
+ payload_size += 1; // suffix_len
+ payload_size += suffix.length(); // suffix
+ payload_size += 8; // data_len
+ payload_size += source_file_size; // data
}
- content_size += 8; // checksum
- Checksum checksum;
AtomicFile atomic_result_file(path, AtomicFile::Mode::binary);
CacheEntryWriter writer(atomic_result_file.stream(),
k_result_magic,
k_result_version,
Compression::type_from_config(),
Compression::level_from_config(),
- content_size,
- checksum);
+ payload_size);
writer.write<uint8_t>(result_file_map.size());
++entry_number;
}
- writer.write(checksum.digest());
writer.finalize();
atomic_result_file.commit();
}