ci: add static analysis, sanitizers, and formatting enforcement #24
@@ -38,8 +38,10 @@ static void print_usage(void) {
|
||||
printf(" --min-size <n> Skip files smaller than n bytes\n");
|
||||
printf(" --incremental Skip files unchanged since last transfer\n");
|
||||
printf(" --delta Delta transfer for changed files (requires --incremental)\n");
|
||||
printf(" --delta-block <n> Delta block size in bytes (default: %d)\n", DELTA_BLOCK_SIZE_DEFAULT);
|
||||
printf(" --delta-max <n> Max file size for delta transfer (default: %llu)\n", DELTA_MAX_FILE_SIZE);
|
||||
printf(" --delta-block <n> Delta block size in bytes (default: %d)\n",
|
||||
DELTA_BLOCK_SIZE_DEFAULT);
|
||||
printf(" --delta-max <n> Max file size for delta transfer (default: %llu)\n",
|
||||
DELTA_MAX_FILE_SIZE);
|
||||
printf(" -m Enable multithreading\n");
|
||||
printf(" -s Enable chunk serialization\n");
|
||||
printf(" -f Enable sendfile (TCP only, not with -c or -s)\n");
|
||||
|
||||
+53
-34
@@ -22,11 +22,12 @@
|
||||
#include <threads.h>
|
||||
#include <time.h>
|
||||
|
||||
static int incremental_check(Client *client, File *file,
|
||||
DeltaSignature **out_sig) {
|
||||
static int incremental_check(Client* client, File* file, DeltaSignature** out_sig) {
|
||||
*out_sig = NULL;
|
||||
if (!send_status(client->file_descriptor, STATUS_CHECK)) return -1;
|
||||
if (!send_str(client->file_descriptor, file->path)) return -1;
|
||||
if (!send_status(client->file_descriptor, STATUS_CHECK))
|
||||
return -1;
|
||||
if (!send_str(client->file_descriptor, file->path))
|
||||
return -1;
|
||||
unsigned long long fsize = file->data->size;
|
||||
long long mtime = file->metadata ? file->metadata->mtime_sec : 0;
|
||||
if (!send_n_data(client->file_descriptor, &fsize, sizeof(fsize)))
|
||||
@@ -40,13 +41,16 @@ static int incremental_check(Client *client, File *file,
|
||||
log_message(LOG_LEVEL_ERROR, "Server reported error for file");
|
||||
return -1;
|
||||
}
|
||||
if (s == STATUS_OK) return 1;
|
||||
if (s == STATUS_OK)
|
||||
return 1;
|
||||
if (s == STATUS_DELTA_SIGNATURE) {
|
||||
Data *sig_data = receive_data(client->file_descriptor);
|
||||
if (!sig_data) return -1;
|
||||
DeltaSignature *sig = delta_signature_deserialize(sig_data);
|
||||
Data* sig_data = receive_data(client->file_descriptor);
|
||||
if (!sig_data)
|
||||
return -1;
|
||||
DeltaSignature* sig = delta_signature_deserialize(sig_data);
|
||||
data_destroy(sig_data);
|
||||
if (!sig) return -1;
|
||||
if (!sig)
|
||||
return -1;
|
||||
*out_sig = sig;
|
||||
return 2;
|
||||
}
|
||||
@@ -57,27 +61,29 @@ static int incremental_check(Client *client, File *file,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_delta(Client *client, File *file, DeltaSignature *sig,
|
||||
Config *config) {
|
||||
Delta *delta = delta_compute(file->data->data, file->data->size,
|
||||
sig, config->delta_block_size);
|
||||
if (!delta) return 1;
|
||||
static int send_delta(Client* client, File* file, DeltaSignature* sig, Config* config) {
|
||||
Delta* delta = delta_compute(file->data->data, file->data->size, sig, config->delta_block_size);
|
||||
if (!delta)
|
||||
return 1;
|
||||
|
||||
if (!delta_is_worthwhile(delta, file->data->size)) {
|
||||
delta_destroy(delta);
|
||||
if (!send_status(client->file_descriptor, STATUS_NEXT)) return -1;
|
||||
if (!send_status(client->file_descriptor, STATUS_NEXT))
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
Data *delta_data = delta_serialize(delta);
|
||||
Data* delta_data = delta_serialize(delta);
|
||||
delta_destroy(delta);
|
||||
if (!delta_data) return -1;
|
||||
if (!delta_data)
|
||||
return -1;
|
||||
|
||||
Data *to_send = delta_data;
|
||||
Data* to_send = delta_data;
|
||||
if (config->use_compression) {
|
||||
to_send = data_compress(delta_data, config->compression_level);
|
||||
data_destroy(delta_data);
|
||||
if (!to_send) return -1;
|
||||
if (!to_send)
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool ok = send_status(client->file_descriptor, STATUS_DELTA_DATA) &&
|
||||
@@ -90,19 +96,26 @@ static int send_delta(Client *client, File *file, DeltaSignature *sig,
|
||||
return ok ? 0 : -1;
|
||||
}
|
||||
|
||||
typedef bool (*file_send_fn)(File *, int, bool, int, bool);
|
||||
typedef bool (*file_send_fn)(File*, int, bool, int, bool);
|
||||
|
||||
static int send_file_incremental(Client *client, File *file, Config *config,
|
||||
file_send_fn send_fn) {
|
||||
DeltaSignature *sig = NULL;
|
||||
static int send_file_incremental(Client* client, File* file, Config* config, file_send_fn send_fn) {
|
||||
DeltaSignature* sig = NULL;
|
||||
int rc = incremental_check(client, file, &sig);
|
||||
if (rc < 0) { delta_signature_destroy(sig); return -1; }
|
||||
if (rc == 1) { delta_signature_destroy(sig); return 1; }
|
||||
if (rc < 0) {
|
||||
delta_signature_destroy(sig);
|
||||
return -1;
|
||||
}
|
||||
if (rc == 1) {
|
||||
delta_signature_destroy(sig);
|
||||
return 1;
|
||||
}
|
||||
if (rc == 2 && config->use_delta) {
|
||||
int drc = send_delta(client, file, sig, config);
|
||||
delta_signature_destroy(sig);
|
||||
if (drc == 0) return 0;
|
||||
if (drc < 0) return -1;
|
||||
if (drc == 0)
|
||||
return 0;
|
||||
if (drc < 0)
|
||||
return -1;
|
||||
} else {
|
||||
delta_signature_destroy(sig);
|
||||
}
|
||||
@@ -112,7 +125,7 @@ static int send_file_incremental(Client *client, File *file, Config *config,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int send_chunk(Client *client, Chunk *chunk, Config *config) {
|
||||
int send_chunk(Client* client, Chunk* chunk, Config* config) {
|
||||
if (config->use_chunk_serialization) {
|
||||
if (!send_status(client->file_descriptor, STATUS_CHUNK))
|
||||
return -1;
|
||||
@@ -134,11 +147,15 @@ int send_chunk(Client *client, Chunk *chunk, Config *config) {
|
||||
if (config->use_incremental) {
|
||||
int rc = send_file_incremental(client, chunk->items[i], config,
|
||||
(file_send_fn)file_send_sendfile);
|
||||
if (rc == 1) continue;
|
||||
if (rc < 0) return -1;
|
||||
if (rc == 1)
|
||||
continue;
|
||||
if (rc < 0)
|
||||
return -1;
|
||||
} else {
|
||||
if (!send_status(client->file_descriptor, STATUS_NEXT)) return -1;
|
||||
if (!file_send_sendfile(chunk->items[i], client->file_descriptor, config->use_metadata, 0, true))
|
||||
if (!send_status(client->file_descriptor, STATUS_NEXT))
|
||||
return -1;
|
||||
if (!file_send_sendfile(chunk->items[i], client->file_descriptor, config->use_metadata, 0,
|
||||
true))
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -147,8 +164,10 @@ int send_chunk(Client *client, Chunk *chunk, Config *config) {
|
||||
if (config->use_incremental) {
|
||||
int rc = send_file_incremental(client, chunk->items[i], config,
|
||||
(file_send_fn)file_send_single_calls);
|
||||
if (rc == 1) continue;
|
||||
if (rc < 0) return -1;
|
||||
if (rc == 1)
|
||||
continue;
|
||||
if (rc < 0)
|
||||
return -1;
|
||||
} else {
|
||||
if (!send_status(client->file_descriptor, STATUS_NEXT))
|
||||
return -1;
|
||||
|
||||
+38
-19
@@ -92,22 +92,38 @@ void config_delete(Config* config) {
|
||||
}
|
||||
|
||||
bool config_send(int file_descriptor, const Config* config) {
|
||||
if (!send_str(file_descriptor, config->version)) return false;
|
||||
if (!send_str(file_descriptor, config->send_directory)) return false;
|
||||
if (!send_str(file_descriptor, config->receive_root_directory)) return false;
|
||||
if (!send_int(file_descriptor, config->save_to_disk)) return false;
|
||||
if (!send_int(file_descriptor, config->use_multithreading)) return false;
|
||||
if (!send_int(file_descriptor, config->use_chunk_serialization)) return false;
|
||||
if (!send_int(file_descriptor, config->use_compression)) return false;
|
||||
if (!send_int(file_descriptor, config->use_metadata)) return false;
|
||||
if (!send_int(file_descriptor, config->compression_level)) return false;
|
||||
if (!send_int(file_descriptor, (int)config->chunk_size)) return false;
|
||||
if (!send_int(file_descriptor, config->use_sendfile)) return false;
|
||||
if (!send_int(file_descriptor, config->use_delete)) return false;
|
||||
if (!send_int(file_descriptor, config->use_incremental)) return false;
|
||||
if (!send_int(file_descriptor, config->use_delta)) return false;
|
||||
if (!send_int(file_descriptor, (int)config->delta_block_size)) return false;
|
||||
if (!send_n_data(file_descriptor, &config->delta_max_file_size, sizeof(unsigned long long))) return false;
|
||||
if (!send_str(file_descriptor, config->version))
|
||||
return false;
|
||||
if (!send_str(file_descriptor, config->send_directory))
|
||||
return false;
|
||||
if (!send_str(file_descriptor, config->receive_root_directory))
|
||||
return false;
|
||||
if (!send_int(file_descriptor, config->save_to_disk))
|
||||
return false;
|
||||
if (!send_int(file_descriptor, config->use_multithreading))
|
||||
return false;
|
||||
if (!send_int(file_descriptor, config->use_chunk_serialization))
|
||||
return false;
|
||||
if (!send_int(file_descriptor, config->use_compression))
|
||||
return false;
|
||||
if (!send_int(file_descriptor, config->use_metadata))
|
||||
return false;
|
||||
if (!send_int(file_descriptor, config->compression_level))
|
||||
return false;
|
||||
if (!send_int(file_descriptor, (int)config->chunk_size))
|
||||
return false;
|
||||
if (!send_int(file_descriptor, config->use_sendfile))
|
||||
return false;
|
||||
if (!send_int(file_descriptor, config->use_delete))
|
||||
return false;
|
||||
if (!send_int(file_descriptor, config->use_incremental))
|
||||
return false;
|
||||
if (!send_int(file_descriptor, config->use_delta))
|
||||
return false;
|
||||
if (!send_int(file_descriptor, (int)config->delta_block_size))
|
||||
return false;
|
||||
if (!send_n_data(file_descriptor, &config->delta_max_file_size, sizeof(unsigned long long)))
|
||||
return false;
|
||||
Status status;
|
||||
if (!receive_status(file_descriptor, &status))
|
||||
return false;
|
||||
@@ -179,11 +195,14 @@ Config* config_receive(int file_descriptor) {
|
||||
if (!receive_int(file_descriptor, &tmp))
|
||||
goto error;
|
||||
config->use_incremental = tmp;
|
||||
if (!receive_int(file_descriptor, &tmp)) goto error;
|
||||
if (!receive_int(file_descriptor, &tmp))
|
||||
goto error;
|
||||
config->use_delta = tmp;
|
||||
if (!receive_int(file_descriptor, &tmp)) goto error;
|
||||
if (!receive_int(file_descriptor, &tmp))
|
||||
goto error;
|
||||
config->delta_block_size = (uint32_t)tmp;
|
||||
if (!receive_n_data(file_descriptor, &config->delta_max_file_size, sizeof(unsigned long long))) goto error;
|
||||
if (!receive_n_data(file_descriptor, &config->delta_max_file_size, sizeof(unsigned long long)))
|
||||
goto error;
|
||||
config->show_progress = false;
|
||||
config->dry_run = false;
|
||||
config->ssh_port = 22;
|
||||
|
||||
+81
-73
@@ -7,8 +7,8 @@
|
||||
#define XXH_IMPLEMENTATION
|
||||
#include <xxhash.h>
|
||||
|
||||
uint32_t delta_adler32(const void *data, uint32_t len) {
|
||||
const uint8_t *p = (const uint8_t *)data;
|
||||
uint32_t delta_adler32(const void* data, uint32_t len) {
|
||||
const uint8_t* p = (const uint8_t*)data;
|
||||
uint32_t s1 = 1;
|
||||
uint32_t s2 = 0;
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
@@ -18,20 +18,20 @@ uint32_t delta_adler32(const void *data, uint32_t len) {
|
||||
return (s2 << 16) | s1;
|
||||
}
|
||||
|
||||
uint32_t delta_xxhash32(const void *data, uint32_t len) {
|
||||
uint32_t delta_xxhash32(const void* data, uint32_t len) {
|
||||
return XXH32(data, len, 0);
|
||||
}
|
||||
|
||||
DeltaSignature *delta_signature_create(const void *old_file_data,
|
||||
uint64_t old_file_size,
|
||||
DeltaSignature* delta_signature_create(const void* old_file_data, uint64_t old_file_size,
|
||||
uint32_t block_size) {
|
||||
if (old_file_data == NULL || old_file_size == 0 || block_size == 0)
|
||||
return NULL;
|
||||
|
||||
uint32_t block_count = (uint32_t)((old_file_size + block_size - 1) / block_size);
|
||||
|
||||
DeltaSignature *sig = malloc(sizeof(DeltaSignature));
|
||||
if (!sig) return NULL;
|
||||
DeltaSignature* sig = malloc(sizeof(DeltaSignature));
|
||||
if (!sig)
|
||||
return NULL;
|
||||
|
||||
sig->file_size = old_file_size;
|
||||
sig->block_size = block_size;
|
||||
@@ -42,12 +42,11 @@ DeltaSignature *delta_signature_create(const void *old_file_data,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const uint8_t *data = (const uint8_t *)old_file_data;
|
||||
const uint8_t* data = (const uint8_t*)old_file_data;
|
||||
for (uint32_t i = 0; i < block_count; i++) {
|
||||
uint64_t offset = (uint64_t)i * block_size;
|
||||
uint32_t len = (uint32_t)((old_file_size - offset < block_size)
|
||||
? (old_file_size - offset)
|
||||
: block_size);
|
||||
uint32_t len =
|
||||
(uint32_t)((old_file_size - offset < block_size) ? (old_file_size - offset) : block_size);
|
||||
sig->blocks[i].adler32 = delta_adler32(data + offset, len);
|
||||
sig->blocks[i].xxhash = delta_xxhash32(data + offset, len);
|
||||
}
|
||||
@@ -55,14 +54,16 @@ DeltaSignature *delta_signature_create(const void *old_file_data,
|
||||
return sig;
|
||||
}
|
||||
|
||||
Data *delta_signature_serialize(const DeltaSignature *sig) {
|
||||
if (!sig) return NULL;
|
||||
Data* delta_signature_serialize(const DeltaSignature* sig) {
|
||||
if (!sig)
|
||||
return NULL;
|
||||
|
||||
uint64_t total = sizeof(uint64_t) + sizeof(uint32_t) + sizeof(uint32_t) +
|
||||
(uint64_t)sig->block_count * (sizeof(uint32_t) + sizeof(uint32_t));
|
||||
|
||||
uint8_t *buf = malloc((size_t)total);
|
||||
if (!buf) return NULL;
|
||||
uint8_t* buf = malloc((size_t)total);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
size_t pos = 0;
|
||||
memcpy(buf + pos, &sig->file_size, sizeof(uint64_t));
|
||||
@@ -82,15 +83,16 @@ Data *delta_signature_serialize(const DeltaSignature *sig) {
|
||||
return data_create(buf, (size_t)total);
|
||||
}
|
||||
|
||||
DeltaSignature *delta_signature_deserialize(const Data *data) {
|
||||
DeltaSignature* delta_signature_deserialize(const Data* data) {
|
||||
if (!data || data->size < sizeof(uint64_t) + sizeof(uint32_t) + sizeof(uint32_t))
|
||||
return NULL;
|
||||
|
||||
const uint8_t *buf = (const uint8_t *)data->data;
|
||||
const uint8_t* buf = (const uint8_t*)data->data;
|
||||
size_t pos = 0;
|
||||
|
||||
DeltaSignature *sig = malloc(sizeof(DeltaSignature));
|
||||
if (!sig) return NULL;
|
||||
DeltaSignature* sig = malloc(sizeof(DeltaSignature));
|
||||
if (!sig)
|
||||
return NULL;
|
||||
|
||||
memcpy(&sig->file_size, buf + pos, sizeof(uint64_t));
|
||||
pos += sizeof(uint64_t);
|
||||
@@ -122,31 +124,35 @@ DeltaSignature *delta_signature_deserialize(const Data *data) {
|
||||
return sig;
|
||||
}
|
||||
|
||||
void delta_signature_destroy(DeltaSignature *sig) {
|
||||
if (!sig) return;
|
||||
void delta_signature_destroy(DeltaSignature* sig) {
|
||||
if (!sig)
|
||||
return;
|
||||
free(sig->blocks);
|
||||
free(sig);
|
||||
}
|
||||
|
||||
static bool ensure_capacity(DeltaInstruction **instrs, uint32_t *capacity,
|
||||
uint32_t count) {
|
||||
if (count < *capacity) return true;
|
||||
static bool ensure_capacity(DeltaInstruction** instrs, uint32_t* capacity, uint32_t count) {
|
||||
if (count < *capacity)
|
||||
return true;
|
||||
uint32_t new_cap = *capacity * 2;
|
||||
DeltaInstruction *tmp = realloc(*instrs, new_cap * sizeof(DeltaInstruction));
|
||||
if (!tmp) return false;
|
||||
DeltaInstruction* tmp = realloc(*instrs, new_cap * sizeof(DeltaInstruction));
|
||||
if (!tmp)
|
||||
return false;
|
||||
*instrs = tmp;
|
||||
*capacity = new_cap;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool flush_literal(DeltaInstruction **instrs, uint32_t *capacity,
|
||||
uint32_t *count, const uint8_t *data,
|
||||
uint64_t start, uint64_t end) {
|
||||
if (start >= end) return true;
|
||||
static bool flush_literal(DeltaInstruction** instrs, uint32_t* capacity, uint32_t* count,
|
||||
const uint8_t* data, uint64_t start, uint64_t end) {
|
||||
if (start >= end)
|
||||
return true;
|
||||
uint32_t lit_len = (uint32_t)(end - start);
|
||||
if (!ensure_capacity(instrs, capacity, *count)) return false;
|
||||
uint8_t *lit_data = malloc(lit_len);
|
||||
if (!lit_data) return false;
|
||||
if (!ensure_capacity(instrs, capacity, *count))
|
||||
return false;
|
||||
uint8_t* lit_data = malloc(lit_len);
|
||||
if (!lit_data)
|
||||
return false;
|
||||
memcpy(lit_data, data + start, lit_len);
|
||||
(*instrs)[*count].type = DELTA_INSTR_LITERAL;
|
||||
(*instrs)[*count].literal.data = lit_data;
|
||||
@@ -155,17 +161,18 @@ static bool flush_literal(DeltaInstruction **instrs, uint32_t *capacity,
|
||||
return true;
|
||||
}
|
||||
|
||||
Delta *delta_compute(const void *new_file_data, uint64_t new_file_size,
|
||||
const DeltaSignature *sig, uint32_t block_size) {
|
||||
Delta* delta_compute(const void* new_file_data, uint64_t new_file_size, const DeltaSignature* sig,
|
||||
uint32_t block_size) {
|
||||
if (!new_file_data || !sig || new_file_size == 0 || block_size == 0)
|
||||
return NULL;
|
||||
|
||||
const uint8_t *new_data = (const uint8_t *)new_file_data;
|
||||
const uint8_t* new_data = (const uint8_t*)new_file_data;
|
||||
|
||||
uint32_t capacity = 64;
|
||||
uint32_t count = 0;
|
||||
DeltaInstruction *instrs = malloc(capacity * sizeof(DeltaInstruction));
|
||||
if (!instrs) return NULL;
|
||||
DeltaInstruction* instrs = malloc(capacity * sizeof(DeltaInstruction));
|
||||
if (!instrs)
|
||||
return NULL;
|
||||
|
||||
uint64_t literal_start = 0;
|
||||
bool has_literal = false;
|
||||
@@ -176,20 +183,17 @@ Delta *delta_compute(const void *new_file_data, uint64_t new_file_size,
|
||||
bool rolling_valid = false;
|
||||
|
||||
while (i < new_file_size) {
|
||||
uint32_t window_len = (uint32_t)((new_file_size - i < block_size)
|
||||
? (new_file_size - i)
|
||||
: block_size);
|
||||
uint32_t window_len =
|
||||
(uint32_t)((new_file_size - i < block_size) ? (new_file_size - i) : block_size);
|
||||
bool full_window = (window_len == block_size);
|
||||
|
||||
uint32_t adler;
|
||||
if (rolling_valid && full_window) {
|
||||
uint8_t old_byte = new_data[i - 1];
|
||||
uint8_t new_byte = new_data[i + block_size - 1];
|
||||
s1 = (s1 + DELTA_ADLER32_MODULUS - old_byte + new_byte) %
|
||||
DELTA_ADLER32_MODULUS;
|
||||
s1 = (s1 + DELTA_ADLER32_MODULUS - old_byte + new_byte) % DELTA_ADLER32_MODULUS;
|
||||
s2 = (s2 + DELTA_ADLER32_MODULUS -
|
||||
(uint32_t)((uint64_t)block_size * old_byte % DELTA_ADLER32_MODULUS) +
|
||||
s1 - 1) %
|
||||
(uint32_t)((uint64_t)block_size * old_byte % DELTA_ADLER32_MODULUS) + s1 - 1) %
|
||||
DELTA_ADLER32_MODULUS;
|
||||
adler = (s2 << 16) | s1;
|
||||
} else {
|
||||
@@ -209,8 +213,7 @@ Delta *delta_compute(const void *new_file_data, uint64_t new_file_size,
|
||||
uint32_t xxh = delta_xxhash32(new_data + i, window_len);
|
||||
if (xxh == sig->blocks[j].xxhash) {
|
||||
if (has_literal) {
|
||||
if (!flush_literal(&instrs, &capacity, &count, new_data,
|
||||
literal_start, i)) {
|
||||
if (!flush_literal(&instrs, &capacity, &count, new_data, literal_start, i)) {
|
||||
free(instrs);
|
||||
return NULL;
|
||||
}
|
||||
@@ -245,14 +248,13 @@ Delta *delta_compute(const void *new_file_data, uint64_t new_file_size,
|
||||
}
|
||||
|
||||
if (has_literal) {
|
||||
if (!flush_literal(&instrs, &capacity, &count, new_data,
|
||||
literal_start, new_file_size)) {
|
||||
if (!flush_literal(&instrs, &capacity, &count, new_data, literal_start, new_file_size)) {
|
||||
free(instrs);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Delta *delta = malloc(sizeof(Delta));
|
||||
Delta* delta = malloc(sizeof(Delta));
|
||||
if (!delta) {
|
||||
for (uint32_t k = 0; k < count; k++) {
|
||||
if (instrs[k].type == DELTA_INSTR_LITERAL)
|
||||
@@ -279,12 +281,14 @@ Delta *delta_compute(const void *new_file_data, uint64_t new_file_size,
|
||||
return delta;
|
||||
}
|
||||
|
||||
Data *delta_serialize(const Delta *delta) {
|
||||
if (!delta) return NULL;
|
||||
Data* delta_serialize(const Delta* delta) {
|
||||
if (!delta)
|
||||
return NULL;
|
||||
|
||||
uint64_t total = sizeof(uint64_t) + sizeof(uint32_t) + delta->delta_size;
|
||||
uint8_t *buf = malloc((size_t)total);
|
||||
if (!buf) return NULL;
|
||||
uint8_t* buf = malloc((size_t)total);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
size_t pos = 0;
|
||||
memcpy(buf + pos, &delta->new_file_size, sizeof(uint64_t));
|
||||
@@ -307,8 +311,7 @@ Data *delta_serialize(const Delta *delta) {
|
||||
} else {
|
||||
memcpy(buf + pos, &delta->instructions[i].literal.length, sizeof(uint32_t));
|
||||
pos += sizeof(uint32_t);
|
||||
memcpy(buf + pos, delta->instructions[i].literal.data,
|
||||
delta->instructions[i].literal.length);
|
||||
memcpy(buf + pos, delta->instructions[i].literal.data, delta->instructions[i].literal.length);
|
||||
pos += delta->instructions[i].literal.length;
|
||||
}
|
||||
}
|
||||
@@ -316,15 +319,16 @@ Data *delta_serialize(const Delta *delta) {
|
||||
return data_create(buf, (size_t)total);
|
||||
}
|
||||
|
||||
Delta *delta_deserialize(const Data *data) {
|
||||
Delta* delta_deserialize(const Data* data) {
|
||||
if (!data || data->size < sizeof(uint64_t) + sizeof(uint32_t))
|
||||
return NULL;
|
||||
|
||||
const uint8_t *buf = (const uint8_t *)data->data;
|
||||
const uint8_t* buf = (const uint8_t*)data->data;
|
||||
size_t pos = 0;
|
||||
|
||||
Delta *delta = malloc(sizeof(Delta));
|
||||
if (!delta) return NULL;
|
||||
Delta* delta = malloc(sizeof(Delta));
|
||||
if (!delta)
|
||||
return NULL;
|
||||
|
||||
memcpy(&delta->new_file_size, buf + pos, sizeof(uint64_t));
|
||||
pos += sizeof(uint64_t);
|
||||
@@ -408,21 +412,22 @@ Delta *delta_deserialize(const Data *data) {
|
||||
return delta;
|
||||
}
|
||||
|
||||
void *delta_apply(const void *old_data, uint64_t old_size, const Delta *delta,
|
||||
void* delta_apply(const void* old_data, uint64_t old_size, const Delta* delta,
|
||||
uint32_t block_size) {
|
||||
if (!old_data || !delta) return NULL;
|
||||
if (!old_data || !delta)
|
||||
return NULL;
|
||||
|
||||
void *output = malloc((size_t)delta->new_file_size);
|
||||
if (!output) return NULL;
|
||||
void* output = malloc((size_t)delta->new_file_size);
|
||||
if (!output)
|
||||
return NULL;
|
||||
|
||||
uint8_t *out = (uint8_t *)output;
|
||||
uint8_t *old = (uint8_t *)old_data;
|
||||
uint8_t* out = (uint8_t*)output;
|
||||
uint8_t* old = (uint8_t*)old_data;
|
||||
uint64_t out_pos = 0;
|
||||
|
||||
for (uint32_t i = 0; i < delta->instruction_count; i++) {
|
||||
if (delta->instructions[i].type == DELTA_INSTR_BLOCK_MATCH) {
|
||||
uint64_t src_offset = (uint64_t)delta->instructions[i].match.block_index *
|
||||
block_size;
|
||||
uint64_t src_offset = (uint64_t)delta->instructions[i].match.block_index * block_size;
|
||||
src_offset += delta->instructions[i].match.block_offset;
|
||||
uint32_t len = delta->instructions[i].match.length;
|
||||
|
||||
@@ -447,8 +452,9 @@ void *delta_apply(const void *old_data, uint64_t old_size, const Delta *delta,
|
||||
return output;
|
||||
}
|
||||
|
||||
void delta_destroy(Delta *delta) {
|
||||
if (!delta) return;
|
||||
void delta_destroy(Delta* delta) {
|
||||
if (!delta)
|
||||
return;
|
||||
for (uint32_t i = 0; i < delta->instruction_count; i++) {
|
||||
if (delta->instructions[i].type == DELTA_INSTR_LITERAL)
|
||||
free(delta->instructions[i].literal.data);
|
||||
@@ -469,8 +475,9 @@ bool delta_should_attempt(uint64_t old_size, uint64_t new_size, uint64_t max_fil
|
||||
return true;
|
||||
}
|
||||
|
||||
bool delta_is_worthwhile(const Delta *delta, uint64_t new_file_size) {
|
||||
if (!delta || delta->instruction_count == 0) return false;
|
||||
bool delta_is_worthwhile(const Delta* delta, uint64_t new_file_size) {
|
||||
if (!delta || delta->instruction_count == 0)
|
||||
return false;
|
||||
|
||||
bool has_match = false;
|
||||
for (uint32_t i = 0; i < delta->instruction_count; i++) {
|
||||
@@ -479,7 +486,8 @@ bool delta_is_worthwhile(const Delta *delta, uint64_t new_file_size) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!has_match) return false;
|
||||
if (!has_match)
|
||||
return false;
|
||||
|
||||
double ratio = (double)delta->delta_size / (double)new_file_size;
|
||||
return ratio < DELTA_FALLBACK_RATIO;
|
||||
|
||||
+16
-21
@@ -27,13 +27,10 @@ typedef struct {
|
||||
uint64_t file_size;
|
||||
uint32_t block_size;
|
||||
uint32_t block_count;
|
||||
DeltaBlockSig *blocks;
|
||||
DeltaBlockSig* blocks;
|
||||
} DeltaSignature;
|
||||
|
||||
typedef enum {
|
||||
DELTA_INSTR_BLOCK_MATCH = 0x01,
|
||||
DELTA_INSTR_LITERAL = 0x02
|
||||
} DeltaInstrType;
|
||||
typedef enum { DELTA_INSTR_BLOCK_MATCH = 0x01, DELTA_INSTR_LITERAL = 0x02 } DeltaInstrType;
|
||||
|
||||
typedef struct {
|
||||
DeltaInstrType type;
|
||||
@@ -44,7 +41,7 @@ typedef struct {
|
||||
uint32_t length;
|
||||
} match;
|
||||
struct {
|
||||
uint8_t *data;
|
||||
uint8_t* data;
|
||||
uint32_t length;
|
||||
} literal;
|
||||
};
|
||||
@@ -53,29 +50,27 @@ typedef struct {
|
||||
typedef struct {
|
||||
uint64_t new_file_size;
|
||||
uint32_t instruction_count;
|
||||
DeltaInstruction *instructions;
|
||||
DeltaInstruction* instructions;
|
||||
uint64_t delta_size;
|
||||
} Delta;
|
||||
|
||||
DeltaSignature *delta_signature_create(const void *old_file_data,
|
||||
uint64_t old_file_size,
|
||||
DeltaSignature* delta_signature_create(const void* old_file_data, uint64_t old_file_size,
|
||||
uint32_t block_size);
|
||||
Data *delta_signature_serialize(const DeltaSignature *sig);
|
||||
DeltaSignature *delta_signature_deserialize(const Data *data);
|
||||
void delta_signature_destroy(DeltaSignature *sig);
|
||||
Data* delta_signature_serialize(const DeltaSignature* sig);
|
||||
DeltaSignature* delta_signature_deserialize(const Data* data);
|
||||
void delta_signature_destroy(DeltaSignature* sig);
|
||||
|
||||
Delta *delta_compute(const void *new_file_data, uint64_t new_file_size,
|
||||
const DeltaSignature *sig, uint32_t block_size);
|
||||
Data *delta_serialize(const Delta *delta);
|
||||
Delta *delta_deserialize(const Data *data);
|
||||
void *delta_apply(const void *old_data, uint64_t old_size, const Delta *delta,
|
||||
Delta* delta_compute(const void* new_file_data, uint64_t new_file_size, const DeltaSignature* sig,
|
||||
uint32_t block_size);
|
||||
void delta_destroy(Delta *delta);
|
||||
Data* delta_serialize(const Delta* delta);
|
||||
Delta* delta_deserialize(const Data* data);
|
||||
void* delta_apply(const void* old_data, uint64_t old_size, const Delta* delta, uint32_t block_size);
|
||||
void delta_destroy(Delta* delta);
|
||||
|
||||
bool delta_should_attempt(uint64_t old_size, uint64_t new_size, uint64_t max_file_size);
|
||||
bool delta_is_worthwhile(const Delta *delta, uint64_t new_file_size);
|
||||
bool delta_is_worthwhile(const Delta* delta, uint64_t new_file_size);
|
||||
|
||||
uint32_t delta_adler32(const void *data, uint32_t len);
|
||||
uint32_t delta_xxhash32(const void *data, uint32_t len);
|
||||
uint32_t delta_adler32(const void* data, uint32_t len);
|
||||
uint32_t delta_xxhash32(const void* data, uint32_t len);
|
||||
|
||||
#endif
|
||||
|
||||
+78
-40
@@ -137,33 +137,50 @@ bool file_save_to_disk(const char* root_directory, File* file) {
|
||||
return ok;
|
||||
}
|
||||
|
||||
static void *old_data_from_path(const char *full_path, unsigned long long old_size) {
|
||||
void *data = malloc((size_t)old_size);
|
||||
if (!data) return NULL;
|
||||
FILE *fp = fopen(full_path, "rb");
|
||||
if (!fp) { free(data); return NULL; }
|
||||
static void* old_data_from_path(const char* full_path, unsigned long long old_size) {
|
||||
void* data = malloc((size_t)old_size);
|
||||
if (!data)
|
||||
return NULL;
|
||||
FILE* fp = fopen(full_path, "rb");
|
||||
if (!fp) {
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
size_t nread = fread(data, 1, (size_t)old_size, fp);
|
||||
fclose(fp);
|
||||
if (nread != (size_t)old_size) { free(data); return NULL; }
|
||||
if (nread != (size_t)old_size) {
|
||||
free(data);
|
||||
return NULL;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
static File *receive_delta_file(int fd, const Config *config, const char *check_path,
|
||||
void *old_data, unsigned long long old_size) {
|
||||
if (!old_data) return NULL;
|
||||
static File* receive_delta_file(int fd, const Config* config, const char* check_path,
|
||||
void* old_data, unsigned long long old_size) {
|
||||
if (!old_data)
|
||||
return NULL;
|
||||
|
||||
DeltaSignature *sig = delta_signature_create(old_data, old_size,
|
||||
config->delta_block_size);
|
||||
if (!sig) { free(old_data); return NULL; }
|
||||
DeltaSignature* sig = delta_signature_create(old_data, old_size, config->delta_block_size);
|
||||
if (!sig) {
|
||||
free(old_data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Data *sig_data = delta_signature_serialize(sig);
|
||||
if (!sig_data) { delta_signature_destroy(sig); free(old_data); return NULL; }
|
||||
Data* sig_data = delta_signature_serialize(sig);
|
||||
if (!sig_data) {
|
||||
delta_signature_destroy(sig);
|
||||
free(old_data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool sig_sent = send_status(fd, STATUS_DELTA_SIGNATURE) &&
|
||||
send_data(fd, sig_data);
|
||||
bool sig_sent = send_status(fd, STATUS_DELTA_SIGNATURE) && send_data(fd, sig_data);
|
||||
data_destroy(sig_data);
|
||||
|
||||
if (!sig_sent) { delta_signature_destroy(sig); free(old_data); return NULL; }
|
||||
if (!sig_sent) {
|
||||
delta_signature_destroy(sig);
|
||||
free(old_data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Status resp;
|
||||
if (!receive_status(fd, &resp)) {
|
||||
@@ -173,7 +190,7 @@ static File *receive_delta_file(int fd, const Config *config, const char *check_
|
||||
}
|
||||
|
||||
if (resp == STATUS_DELTA_DATA) {
|
||||
Data *delta_data = receive_data(fd);
|
||||
Data* delta_data = receive_data(fd);
|
||||
if (!delta_data) {
|
||||
delta_signature_destroy(sig);
|
||||
free(old_data);
|
||||
@@ -181,7 +198,7 @@ static File *receive_delta_file(int fd, const Config *config, const char *check_
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Data *raw_delta = delta_data;
|
||||
Data* raw_delta = delta_data;
|
||||
if (config->use_compression) {
|
||||
raw_delta = data_decompress(delta_data);
|
||||
data_destroy(delta_data);
|
||||
@@ -193,7 +210,7 @@ static File *receive_delta_file(int fd, const Config *config, const char *check_
|
||||
}
|
||||
}
|
||||
|
||||
Delta *delta = delta_deserialize(raw_delta);
|
||||
Delta* delta = delta_deserialize(raw_delta);
|
||||
data_destroy(raw_delta);
|
||||
if (!delta) {
|
||||
free(old_data);
|
||||
@@ -202,8 +219,7 @@ static File *receive_delta_file(int fd, const Config *config, const char *check_
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *new_data = delta_apply(old_data, old_size, delta,
|
||||
config->delta_block_size);
|
||||
void* new_data = delta_apply(old_data, old_size, delta, config->delta_block_size);
|
||||
uint64_t new_size = delta->new_file_size;
|
||||
delta_destroy(delta);
|
||||
|
||||
@@ -214,7 +230,7 @@ static File *receive_delta_file(int fd, const Config *config, const char *check_
|
||||
return NULL;
|
||||
}
|
||||
|
||||
File *file = file_create(check_path);
|
||||
File* file = file_create(check_path);
|
||||
if (!file) {
|
||||
free(new_data);
|
||||
free(old_data);
|
||||
@@ -248,16 +264,23 @@ static File *receive_delta_file(int fd, const Config *config, const char *check_
|
||||
delta_signature_destroy(sig);
|
||||
free(old_data);
|
||||
|
||||
File *file = file_create(check_path);
|
||||
if (!file) { send_status(fd, STATUS_ERROR); return NULL; }
|
||||
File* file = file_create(check_path);
|
||||
if (!file) {
|
||||
send_status(fd, STATUS_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (config->use_metadata) {
|
||||
int meta_ok = 1;
|
||||
file->metadata = metadata_receive(fd, &meta_ok);
|
||||
if (!meta_ok) { file_destroy(file); send_status(fd, STATUS_ERROR); return NULL; }
|
||||
if (!meta_ok) {
|
||||
file_destroy(file);
|
||||
send_status(fd, STATUS_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Data *file_data = receive_data(fd);
|
||||
Data* file_data = receive_data(fd);
|
||||
if (file_data == NULL) {
|
||||
file_destroy(file);
|
||||
send_status(fd, STATUS_ERROR);
|
||||
@@ -265,9 +288,13 @@ static File *receive_delta_file(int fd, const Config *config, const char *check_
|
||||
}
|
||||
|
||||
if (config->use_compression) {
|
||||
Data *uncompressed = data_decompress(file_data);
|
||||
Data* uncompressed = data_decompress(file_data);
|
||||
data_destroy(file_data);
|
||||
if (uncompressed == NULL) { file_destroy(file); send_status(fd, STATUS_ERROR); return NULL; }
|
||||
if (uncompressed == NULL) {
|
||||
file_destroy(file);
|
||||
send_status(fd, STATUS_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
file_data = uncompressed;
|
||||
}
|
||||
|
||||
@@ -284,7 +311,10 @@ static File *receive_delta_file(int fd, const Config *config, const char *check_
|
||||
File* receive_incremental_check(int fd, const Config* config, bool* skipped) {
|
||||
*skipped = false;
|
||||
char* check_path = receive_str(fd);
|
||||
if (check_path == NULL) { send_status(fd, STATUS_ERROR); return NULL; }
|
||||
if (check_path == NULL) {
|
||||
send_status(fd, STATUS_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned long long check_size;
|
||||
long long check_mtime;
|
||||
@@ -300,12 +330,15 @@ File* receive_incremental_check(int fd, const Config* config, bool* skipped) {
|
||||
bool has_old_file = (full_path && stat(full_path, &st) == 0);
|
||||
unsigned long long old_size = has_old_file ? (unsigned long long)st.st_size : 0;
|
||||
|
||||
bool match = has_old_file &&
|
||||
(unsigned long long)st.st_size == check_size &&
|
||||
bool match = has_old_file && (unsigned long long)st.st_size == check_size &&
|
||||
(long long)st.st_mtime == check_mtime;
|
||||
|
||||
if (match) {
|
||||
if (!send_status(fd, STATUS_OK)) { free(full_path); free(check_path); return NULL; }
|
||||
if (!send_status(fd, STATUS_OK)) {
|
||||
free(full_path);
|
||||
free(check_path);
|
||||
return NULL;
|
||||
}
|
||||
free(full_path);
|
||||
free(check_path);
|
||||
*skipped = true;
|
||||
@@ -316,9 +349,8 @@ File* receive_incremental_check(int fd, const Config* config, bool* skipped) {
|
||||
delta_should_attempt(old_size, check_size, config->delta_max_file_size);
|
||||
|
||||
if (try_delta) {
|
||||
void *old_data = old_data_from_path(full_path, old_size);
|
||||
File *delta_file = receive_delta_file(fd, config, check_path,
|
||||
old_data, old_size);
|
||||
void* old_data = old_data_from_path(full_path, old_size);
|
||||
File* delta_file = receive_delta_file(fd, config, check_path, old_data, old_size);
|
||||
if (delta_file) {
|
||||
free(full_path);
|
||||
free(check_path);
|
||||
@@ -338,7 +370,10 @@ File* receive_incremental_check(int fd, const Config* config, bool* skipped) {
|
||||
File* file = file_create(check_path);
|
||||
free(check_path);
|
||||
free(full_path);
|
||||
if (file == NULL) { send_status(fd, STATUS_ERROR); return NULL; }
|
||||
if (file == NULL) {
|
||||
send_status(fd, STATUS_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (config->use_metadata) {
|
||||
int meta_ok = 1;
|
||||
@@ -398,10 +433,13 @@ bool to_disk(const char* path, const void* data, unsigned long long data_size) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool file_send_sendfile(File *file, int file_descriptor, bool use_metadata, int compression_level, bool send_path) {
|
||||
bool file_send_sendfile(File* file, int file_descriptor, bool use_metadata, int compression_level,
|
||||
bool send_path) {
|
||||
(void)compression_level;
|
||||
if (send_path && !send_str(file_descriptor, file->path)) return false;
|
||||
if (use_metadata && !metadata_send(file_descriptor, file->metadata)) return false;
|
||||
if (send_path && !send_str(file_descriptor, file->path))
|
||||
return false;
|
||||
if (use_metadata && !metadata_send(file_descriptor, file->metadata))
|
||||
return false;
|
||||
|
||||
int fd = open(file->path, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
|
||||
+2
-2
@@ -26,8 +26,8 @@ bool file_load_data(File* file);
|
||||
File* file_receive(const Config* config, int file_descriptor);
|
||||
bool file_send_single_calls(File* file, int file_descriptor, bool use_metadata,
|
||||
int compression_level, bool send_path);
|
||||
bool file_send_sendfile(File* file, int file_descriptor, bool use_metadata,
|
||||
int compression_level, bool send_path);
|
||||
bool file_send_sendfile(File* file, int file_descriptor, bool use_metadata, int compression_level,
|
||||
bool send_path);
|
||||
size_t file_content_to_buffer(File* file);
|
||||
FileMetadata* file_metadata_create(const struct stat* stats);
|
||||
void file_metadata_destroy(void* metadata);
|
||||
|
||||
+46
-40
@@ -4,7 +4,7 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
static void test_adler32_basic() {
|
||||
const char *data = "Hello";
|
||||
const char* data = "Hello";
|
||||
uint32_t h = delta_adler32(data, 5);
|
||||
EXPECT_TRUE(h != 0);
|
||||
uint32_t h2 = delta_adler32(data, 5);
|
||||
@@ -12,15 +12,15 @@ static void test_adler32_basic() {
|
||||
}
|
||||
|
||||
static void test_adler32_different_data() {
|
||||
const char *a = "AAAA";
|
||||
const char *b = "BBBB";
|
||||
const char* a = "AAAA";
|
||||
const char* b = "BBBB";
|
||||
uint32_t ha = delta_adler32(a, 4);
|
||||
uint32_t hb = delta_adler32(b, 4);
|
||||
EXPECT_TRUE(ha != hb);
|
||||
}
|
||||
|
||||
static void test_xxhash32_basic() {
|
||||
const char *data = "Hello";
|
||||
const char* data = "Hello";
|
||||
uint32_t h = delta_xxhash32(data, 5);
|
||||
EXPECT_TRUE(h != 0);
|
||||
uint32_t h2 = delta_xxhash32(data, 5);
|
||||
@@ -28,8 +28,8 @@ static void test_xxhash32_basic() {
|
||||
}
|
||||
|
||||
static void test_xxhash32_different_data() {
|
||||
const char *a = "AAAA";
|
||||
const char *b = "BBBB";
|
||||
const char* a = "AAAA";
|
||||
const char* b = "BBBB";
|
||||
uint32_t ha = delta_xxhash32(a, 4);
|
||||
uint32_t hb = delta_xxhash32(b, 4);
|
||||
EXPECT_TRUE(ha != hb);
|
||||
@@ -37,17 +37,18 @@ static void test_xxhash32_different_data() {
|
||||
|
||||
static void test_signature_roundtrip() {
|
||||
char old_data[4096];
|
||||
for (int i = 0; i < 4096; i++) old_data[i] = (char)(i % 256);
|
||||
for (int i = 0; i < 4096; i++)
|
||||
old_data[i] = (char)(i % 256);
|
||||
|
||||
DeltaSignature *sig = delta_signature_create(old_data, 4096, 1024);
|
||||
DeltaSignature* sig = delta_signature_create(old_data, 4096, 1024);
|
||||
EXPECT_NOT_NULL(sig);
|
||||
EXPECT_EQ_INT((int)sig->block_count, 4);
|
||||
EXPECT_EQ_INT((int)sig->block_size, 1024);
|
||||
|
||||
Data *serialized = delta_signature_serialize(sig);
|
||||
Data* serialized = delta_signature_serialize(sig);
|
||||
EXPECT_NOT_NULL(serialized);
|
||||
|
||||
DeltaSignature *deserialized = delta_signature_deserialize(serialized);
|
||||
DeltaSignature* deserialized = delta_signature_deserialize(serialized);
|
||||
EXPECT_NOT_NULL(deserialized);
|
||||
EXPECT_EQ_INT((int)deserialized->block_count, (int)sig->block_count);
|
||||
EXPECT_EQ_INT((int)deserialized->block_size, (int)sig->block_size);
|
||||
@@ -64,12 +65,13 @@ static void test_signature_roundtrip() {
|
||||
|
||||
static void test_delta_identical_files() {
|
||||
char data[2048];
|
||||
for (int i = 0; i < 2048; i++) data[i] = (char)(i % 128);
|
||||
for (int i = 0; i < 2048; i++)
|
||||
data[i] = (char)(i % 128);
|
||||
|
||||
DeltaSignature *sig = delta_signature_create(data, 2048, 512);
|
||||
DeltaSignature* sig = delta_signature_create(data, 2048, 512);
|
||||
EXPECT_NOT_NULL(sig);
|
||||
|
||||
Delta *delta = delta_compute(data, 2048, sig, 512);
|
||||
Delta* delta = delta_compute(data, 2048, sig, 512);
|
||||
EXPECT_NOT_NULL(delta);
|
||||
|
||||
bool has_match = false;
|
||||
@@ -105,10 +107,10 @@ static void test_delta_small_edit() {
|
||||
new_data[101] = 'Y';
|
||||
new_data[102] = 'Z';
|
||||
|
||||
DeltaSignature *sig = delta_signature_create(old_data, 4096, 1024);
|
||||
DeltaSignature* sig = delta_signature_create(old_data, 4096, 1024);
|
||||
EXPECT_NOT_NULL(sig);
|
||||
|
||||
Delta *delta = delta_compute(new_data, 4096, sig, 1024);
|
||||
Delta* delta = delta_compute(new_data, 4096, sig, 1024);
|
||||
EXPECT_NOT_NULL(delta);
|
||||
|
||||
uint64_t total_literal = 0;
|
||||
@@ -122,7 +124,7 @@ static void test_delta_small_edit() {
|
||||
EXPECT_TRUE(match_count > 0);
|
||||
EXPECT_TRUE(total_literal < 4096);
|
||||
|
||||
void *reconstructed = delta_apply(old_data, 4096, delta, 1024);
|
||||
void* reconstructed = delta_apply(old_data, 4096, delta, 1024);
|
||||
EXPECT_NOT_NULL(reconstructed);
|
||||
EXPECT_EQ_INT(memcmp(reconstructed, new_data, 4096), 0);
|
||||
|
||||
@@ -139,10 +141,10 @@ static void test_delta_completely_different() {
|
||||
new_data[i] = (char)(i * 13 + 97);
|
||||
}
|
||||
|
||||
DeltaSignature *sig = delta_signature_create(old_data, 4096, 1024);
|
||||
DeltaSignature* sig = delta_signature_create(old_data, 4096, 1024);
|
||||
EXPECT_NOT_NULL(sig);
|
||||
|
||||
Delta *delta = delta_compute(new_data, 4096, sig, 1024);
|
||||
Delta* delta = delta_compute(new_data, 4096, sig, 1024);
|
||||
EXPECT_NOT_NULL(delta);
|
||||
|
||||
bool has_match = false;
|
||||
@@ -169,19 +171,19 @@ static void test_delta_serialize_roundtrip() {
|
||||
new_data[500] = 'A';
|
||||
new_data[501] = 'B';
|
||||
|
||||
DeltaSignature *sig = delta_signature_create(old_data, 4096, 1024);
|
||||
Delta *delta = delta_compute(new_data, 4096, sig, 1024);
|
||||
DeltaSignature* sig = delta_signature_create(old_data, 4096, 1024);
|
||||
Delta* delta = delta_compute(new_data, 4096, sig, 1024);
|
||||
EXPECT_NOT_NULL(delta);
|
||||
|
||||
Data *serialized = delta_serialize(delta);
|
||||
Data* serialized = delta_serialize(delta);
|
||||
EXPECT_NOT_NULL(serialized);
|
||||
|
||||
Delta *deserialized = delta_deserialize(serialized);
|
||||
Delta* deserialized = delta_deserialize(serialized);
|
||||
EXPECT_NOT_NULL(deserialized);
|
||||
EXPECT_EQ_INT((int)deserialized->new_file_size, (int)delta->new_file_size);
|
||||
EXPECT_EQ_INT((int)deserialized->instruction_count, (int)delta->instruction_count);
|
||||
|
||||
void *reconstructed = delta_apply(old_data, 4096, deserialized, 1024);
|
||||
void* reconstructed = delta_apply(old_data, 4096, deserialized, 1024);
|
||||
EXPECT_NOT_NULL(reconstructed);
|
||||
EXPECT_EQ_INT(memcmp(reconstructed, new_data, 4096), 0);
|
||||
|
||||
@@ -195,17 +197,19 @@ static void test_delta_serialize_roundtrip() {
|
||||
static void test_delta_file_growth() {
|
||||
char old_data[2048];
|
||||
char new_data[3072];
|
||||
for (int i = 0; i < 2048; i++) old_data[i] = (char)(i % 256);
|
||||
for (int i = 0; i < 2048; i++)
|
||||
old_data[i] = (char)(i % 256);
|
||||
memcpy(new_data, old_data, 2048);
|
||||
for (int i = 2048; i < 3072; i++) new_data[i] = (char)(i % 256);
|
||||
for (int i = 2048; i < 3072; i++)
|
||||
new_data[i] = (char)(i % 256);
|
||||
|
||||
DeltaSignature *sig = delta_signature_create(old_data, 2048, 512);
|
||||
DeltaSignature* sig = delta_signature_create(old_data, 2048, 512);
|
||||
EXPECT_NOT_NULL(sig);
|
||||
|
||||
Delta *delta = delta_compute(new_data, 3072, sig, 512);
|
||||
Delta* delta = delta_compute(new_data, 3072, sig, 512);
|
||||
EXPECT_NOT_NULL(delta);
|
||||
|
||||
void *reconstructed = delta_apply(old_data, 2048, delta, 512);
|
||||
void* reconstructed = delta_apply(old_data, 2048, delta, 512);
|
||||
EXPECT_NOT_NULL(reconstructed);
|
||||
EXPECT_EQ_INT(delta->new_file_size, 3072);
|
||||
EXPECT_EQ_INT(memcmp(reconstructed, new_data, 3072), 0);
|
||||
@@ -218,16 +222,18 @@ static void test_delta_file_growth() {
|
||||
static void test_delta_file_shrink() {
|
||||
char old_data[3072];
|
||||
char new_data[2048];
|
||||
for (int i = 0; i < 3072; i++) old_data[i] = (char)(i % 256);
|
||||
for (int i = 0; i < 2048; i++) new_data[i] = old_data[i];
|
||||
for (int i = 0; i < 3072; i++)
|
||||
old_data[i] = (char)(i % 256);
|
||||
for (int i = 0; i < 2048; i++)
|
||||
new_data[i] = old_data[i];
|
||||
|
||||
DeltaSignature *sig = delta_signature_create(old_data, 3072, 512);
|
||||
DeltaSignature* sig = delta_signature_create(old_data, 3072, 512);
|
||||
EXPECT_NOT_NULL(sig);
|
||||
|
||||
Delta *delta = delta_compute(new_data, 2048, sig, 512);
|
||||
Delta* delta = delta_compute(new_data, 2048, sig, 512);
|
||||
EXPECT_NOT_NULL(delta);
|
||||
|
||||
void *reconstructed = delta_apply(old_data, 3072, delta, 512);
|
||||
void* reconstructed = delta_apply(old_data, 3072, delta, 512);
|
||||
EXPECT_NOT_NULL(reconstructed);
|
||||
EXPECT_EQ_INT(delta->new_file_size, 2048);
|
||||
EXPECT_EQ_INT(memcmp(reconstructed, new_data, 2048), 0);
|
||||
@@ -273,24 +279,24 @@ static void test_large_file_delta() {
|
||||
uint64_t old_size = 200000;
|
||||
uint64_t new_size = 200000;
|
||||
|
||||
void *old_data = malloc((size_t)old_size);
|
||||
void *new_data = malloc((size_t)new_size);
|
||||
void* old_data = malloc((size_t)old_size);
|
||||
void* new_data = malloc((size_t)new_size);
|
||||
EXPECT_TRUE(old_data != NULL && new_data != NULL);
|
||||
|
||||
for (uint64_t i = 0; i < old_size; i++)
|
||||
((uint8_t *)old_data)[i] = (uint8_t)(i % 251);
|
||||
((uint8_t*)old_data)[i] = (uint8_t)(i % 251);
|
||||
memcpy(new_data, old_data, (size_t)old_size);
|
||||
|
||||
uint64_t offset = 100000;
|
||||
uint32_t change_len = 4096;
|
||||
for (uint32_t i = 0; i < change_len; i++)
|
||||
((uint8_t *)new_data)[offset + i] = (uint8_t)((i * 7 + 13) % 256);
|
||||
((uint8_t*)new_data)[offset + i] = (uint8_t)((i * 7 + 13) % 256);
|
||||
|
||||
DeltaSignature *sig = delta_signature_create(old_data, old_size, block_size);
|
||||
DeltaSignature* sig = delta_signature_create(old_data, old_size, block_size);
|
||||
EXPECT_TRUE(sig != NULL);
|
||||
EXPECT_TRUE(sig->block_count == (uint32_t)((old_size + block_size - 1) / block_size));
|
||||
|
||||
Delta *delta = delta_compute(new_data, new_size, sig, block_size);
|
||||
Delta* delta = delta_compute(new_data, new_size, sig, block_size);
|
||||
EXPECT_TRUE(delta != NULL);
|
||||
|
||||
uint64_t total_literal = 0;
|
||||
@@ -304,7 +310,7 @@ static void test_large_file_delta() {
|
||||
EXPECT_TRUE(match_count > 0);
|
||||
EXPECT_TRUE(delta->delta_size < new_size / 2);
|
||||
|
||||
void *result = delta_apply(old_data, old_size, delta, block_size);
|
||||
void* result = delta_apply(old_data, old_size, delta, block_size);
|
||||
EXPECT_TRUE(result != NULL);
|
||||
EXPECT_TRUE(delta->new_file_size == new_size);
|
||||
EXPECT_TRUE(memcmp(result, new_data, (size_t)new_size) == 0);
|
||||
|
||||
Reference in New Issue
Block a user