Merge remote-tracking branch 'origin/main' into ci/tier1-review-automation
CI / lint (push) Failing after 3s
CI / build-and-test (push) Has been skipped
CI / sanitizers (address) (push) Has been skipped
CI / lint (pull_request) Failing after 2s
CI / build-and-test (pull_request) Has been skipped
CI / sanitizers (address) (pull_request) Has been skipped

# Conflicts:
#	src/client/client_send.c
#	src/shared/config.c
#	src/shared/file.c
#	src/shared/file.h
#	src/shared/protocol.h
This commit is contained in:
2026-07-19 16:58:53 +02:00
14 changed files with 1260 additions and 86 deletions
+181 -26
View File
@@ -10,6 +10,7 @@
#include <unistd.h>
#include "compression.h"
#include "delta.h"
#include "log.h"
#include "config.h"
#include "data.h"
@@ -136,13 +137,154 @@ 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; }
size_t nread = fread(data, 1, (size_t)old_size, fp);
fclose(fp);
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;
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; }
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; }
Status resp;
if (!receive_status(fd, &resp)) {
delta_signature_destroy(sig);
free(old_data);
return NULL;
}
if (resp == STATUS_DELTA_DATA) {
Data *delta_data = receive_data(fd);
if (!delta_data) {
delta_signature_destroy(sig);
free(old_data);
send_status(fd, STATUS_ERROR);
return NULL;
}
Data *raw_delta = delta_data;
if (config->use_compression) {
raw_delta = data_decompress(delta_data);
data_destroy(delta_data);
if (!raw_delta) {
free(old_data);
delta_signature_destroy(sig);
send_status(fd, STATUS_ERROR);
return NULL;
}
}
Delta *delta = delta_deserialize(raw_delta);
data_destroy(raw_delta);
if (!delta) {
free(old_data);
delta_signature_destroy(sig);
send_status(fd, STATUS_ERROR);
return NULL;
}
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);
if (!new_data) {
free(old_data);
delta_signature_destroy(sig);
send_status(fd, STATUS_ERROR);
return NULL;
}
File *file = file_create(check_path);
if (!file) {
free(new_data);
free(old_data);
delta_signature_destroy(sig);
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);
free(new_data);
free(old_data);
delta_signature_destroy(sig);
send_status(fd, STATUS_ERROR);
return NULL;
}
}
data_destroy(file->data);
file->data = data_create(new_data, (size_t)new_size);
free(old_data);
delta_signature_destroy(sig);
return file;
}
if (resp == STATUS_NEXT) {
delta_signature_destroy(sig);
free(old_data);
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; }
}
Data *file_data = receive_data(fd);
if (file_data == NULL) {
file_destroy(file);
send_status(fd, STATUS_ERROR);
return NULL;
}
if (config->use_compression) {
Data *uncompressed = data_decompress(file_data);
data_destroy(file_data);
if (uncompressed == NULL) { file_destroy(file); send_status(fd, STATUS_ERROR); return NULL; }
file_data = uncompressed;
}
data_destroy(file->data);
file->data = file_data;
return file;
}
delta_signature_destroy(sig);
free(old_data);
return NULL;
}
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;
@@ -155,34 +297,48 @@ File* receive_incremental_check(int fd, const Config* config, bool* skipped) {
char* full_path = path_cat(config->receive_root_directory, check_path);
struct stat st;
bool match = false;
if (full_path && stat(full_path, &st) == 0 && (unsigned long long)st.st_size == check_size &&
(long long)st.st_mtime == check_mtime) {
match = true;
}
free(full_path);
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 &&
(long long)st.st_mtime == check_mtime;
if (match) {
if (!send_status(fd, STATUS_OK)) {
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;
return NULL;
}
if (!send_status(fd, STATUS_NEXT)) {
free(check_path);
return NULL;
bool try_delta = config->use_delta && has_old_file &&
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);
if (delta_file) {
free(full_path);
free(check_path);
return delta_file;
}
try_delta = false;
}
if (!try_delta) {
if (!send_status(fd, STATUS_NEXT)) {
free(full_path);
free(check_path);
return NULL;
}
}
File* file = file_create(check_path);
free(check_path);
if (file == NULL) {
send_status(fd, STATUS_ERROR);
return NULL;
}
free(full_path);
if (file == NULL) { send_status(fd, STATUS_ERROR); return NULL; }
if (config->use_metadata) {
int meta_ok = 1;
@@ -242,11 +398,10 @@ 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, bool send_path) {
if (send_path && !send_str(file_descriptor, file->path))
return false;
if (use_metadata && !metadata_send(file_descriptor, file->metadata))
return false;
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;
int fd = open(file->path, O_RDONLY);
if (fd == -1) {