feat: add rsync modify-window option
CI / lint (pull_request) Successful in 14s
CI / sanitizers (address) (pull_request) Successful in 37s
CI / sanitizers (undefined) (pull_request) Successful in 38s
CI / fuzz-build (pull_request) Successful in 15s
CI / coverage (pull_request) Successful in 31s
CI / build-and-test (pull_request) Failing after 1m15s
CI / valgrind (pull_request) Successful in 32s
CI / lint (pull_request) Successful in 14s
CI / sanitizers (address) (pull_request) Successful in 37s
CI / sanitizers (undefined) (pull_request) Successful in 38s
CI / fuzz-build (pull_request) Successful in 15s
CI / coverage (pull_request) Successful in 31s
CI / build-and-test (pull_request) Failing after 1m15s
CI / valgrind (pull_request) Successful in 32s
This commit is contained in:
+7
-2
@@ -35,6 +35,7 @@ static void config_set_defaults(Config* config) {
|
||||
config->min_size = 0;
|
||||
config->use_incremental = false;
|
||||
config->use_delta = false;
|
||||
config->modify_window = 0;
|
||||
config->delta_block_size = DELTA_BLOCK_SIZE_DEFAULT;
|
||||
config->delta_max_file_size = DELTA_MAX_FILE_SIZE;
|
||||
config->use_tls = false;
|
||||
@@ -134,7 +135,8 @@ static bool validate_received_config(const Config* config) {
|
||||
config->chunk_size > 0 && config->chunk_size <= MAX_CHUNK_SIZE &&
|
||||
config->delta_block_size >= DELTA_BLOCK_SIZE_MIN &&
|
||||
config->delta_block_size <= DELTA_BLOCK_SIZE_MAX &&
|
||||
config->delta_max_file_size <= DELTA_MAX_FILE_SIZE && config->max_delete >= 0;
|
||||
config->delta_max_file_size <= DELTA_MAX_FILE_SIZE && config->modify_window >= 0 &&
|
||||
config->max_delete >= 0;
|
||||
}
|
||||
|
||||
Config* config_create(void) {
|
||||
@@ -253,7 +255,8 @@ static bool send_resume_options(int fd, const Config* c) {
|
||||
return send_str(fd, c->temp_dir ? c->temp_dir : "") && send_int(fd, c->partial) &&
|
||||
send_str(fd, c->partial_dir ? c->partial_dir : "") &&
|
||||
send_str(fd, c->suffix ? c->suffix : "") && send_int(fd, c->delete_before) &&
|
||||
send_int(fd, c->checksum) && send_str(fd, c->compress_choice ? c->compress_choice : "");
|
||||
send_int(fd, c->checksum) && send_int(fd, c->modify_window) &&
|
||||
send_str(fd, c->compress_choice ? c->compress_choice : "");
|
||||
}
|
||||
|
||||
static bool receive_core_fields(int fd, Config* c) {
|
||||
@@ -329,6 +332,8 @@ static bool receive_resume_options(int fd, Config* c) {
|
||||
return false;
|
||||
if (!receive_wire_bool(fd, &c->checksum))
|
||||
return false;
|
||||
if (!receive_n_data(fd, &c->modify_window, sizeof(c->modify_window)))
|
||||
return false;
|
||||
c->compress_choice = receive_str(fd);
|
||||
return c->compress_choice != NULL;
|
||||
}
|
||||
|
||||
+2
-1
@@ -35,6 +35,7 @@ typedef struct Config {
|
||||
unsigned long long min_size;
|
||||
bool use_incremental;
|
||||
bool use_delta;
|
||||
int modify_window;
|
||||
uint32_t delta_block_size;
|
||||
unsigned long long delta_max_file_size;
|
||||
bool use_tls;
|
||||
@@ -128,7 +129,7 @@ typedef struct Config {
|
||||
char* compress_choice;
|
||||
} Config;
|
||||
|
||||
#define PROTOCOL_VERSION "2.2.0"
|
||||
#define PROTOCOL_VERSION "2.3.0"
|
||||
#define DEFAULT_CHUNK_SIZE (10 * 1024 * 1024)
|
||||
|
||||
Config* config_create(void);
|
||||
|
||||
@@ -314,12 +314,19 @@ File* receive_incremental_check(int fd, const Config* config, bool* skipped) {
|
||||
|
||||
unsigned long long check_size;
|
||||
long long check_mtime;
|
||||
long long check_mtime_nsec;
|
||||
uint64_t check_checksum = 0;
|
||||
if (!receive_n_data(fd, &check_size, sizeof(check_size)) ||
|
||||
!receive_n_data(fd, &check_mtime, sizeof(check_mtime))) {
|
||||
free(check_path);
|
||||
return NULL;
|
||||
}
|
||||
if (!receive_n_data(fd, &check_mtime_nsec, sizeof(check_mtime_nsec)) || check_mtime_nsec < 0 ||
|
||||
check_mtime_nsec >= 1000000000LL) {
|
||||
free(check_path);
|
||||
send_status(fd, STATUS_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
if (config->checksum && !receive_n_data(fd, &check_checksum, sizeof(check_checksum))) {
|
||||
free(check_path);
|
||||
return NULL;
|
||||
@@ -384,7 +391,12 @@ File* receive_incremental_check(int fd, const Config* config, bool* skipped) {
|
||||
free(old_data);
|
||||
old_data = NULL;
|
||||
} else if (match) {
|
||||
match = (long long)st.st_mtime == check_mtime;
|
||||
long long old_mtime_nsec = 0;
|
||||
#ifdef __linux__
|
||||
old_mtime_nsec = st.st_mtim.tv_nsec;
|
||||
#endif
|
||||
match = metadata_mtime_matches(st.st_mtime, old_mtime_nsec, (time_t)check_mtime,
|
||||
(long)check_mtime_nsec, config->modify_window);
|
||||
}
|
||||
|
||||
if (match) {
|
||||
|
||||
@@ -24,6 +24,23 @@ typedef char static_assert_mode_t_fits[(sizeof(mode_t) <= sizeof(int32_t)) ? 1 :
|
||||
typedef char static_assert_uid_t_fits[(sizeof(uid_t) <= sizeof(int32_t)) ? 1 : -1];
|
||||
typedef char static_assert_gid_t_fits[(sizeof(gid_t) <= sizeof(int32_t)) ? 1 : -1];
|
||||
|
||||
bool metadata_mtime_matches(time_t left_sec, long left_nsec, time_t right_sec, long right_nsec,
|
||||
int modify_window) {
|
||||
int64_t left = (int64_t)left_sec;
|
||||
int64_t right = (int64_t)right_sec;
|
||||
int64_t seconds;
|
||||
int64_t nanoseconds;
|
||||
|
||||
if (left > right || (left == right && left_nsec >= right_nsec)) {
|
||||
seconds = left - right;
|
||||
nanoseconds = (int64_t)left_nsec - (int64_t)right_nsec;
|
||||
} else {
|
||||
seconds = right - left;
|
||||
nanoseconds = (int64_t)right_nsec - (int64_t)left_nsec;
|
||||
}
|
||||
return seconds < modify_window || (seconds == modify_window && nanoseconds == 0);
|
||||
}
|
||||
|
||||
void metadata_to_buf(char** buf, const FileMetadata* m) {
|
||||
int32_t present = (m != NULL) ? 1 : 0;
|
||||
memcpy(*buf, &present, sizeof(present));
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
|
||||
/*
|
||||
* Wire format (introduced in protocol version 2.0.0):
|
||||
@@ -32,4 +33,8 @@ FileMetadata* metadata_receive(int file_descriptor, int* ok);
|
||||
void file_restore_metadata(const char* path, const FileMetadata* metadata);
|
||||
bool file_restore_metadata_fd(int fd, const FileMetadata* metadata);
|
||||
|
||||
/* Compare timestamps using rsync's whole-second modification window. */
|
||||
bool metadata_mtime_matches(time_t left_sec, long left_nsec, time_t right_sec, long right_nsec,
|
||||
int modify_window);
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user