Comprehensive fix: security, bugs, refactoring, tests, and rsync parity features #173

Merged
TapTap merged 16 commits from integration/all-fixes into main 2026-07-30 18:13:15 +02:00
9 changed files with 80 additions and 73 deletions
Showing only changes of commit 7d8f593844 - Show all commits
+18 -9
View File
@@ -311,7 +311,8 @@ static int parse_args(Config* config, int argc, char* argv[], int* positional_ar
config->itemize_changes = true; config->itemize_changes = true;
} else if (strcmp(argv[i], "--out-format") == 0 && i + 1 < argc) { } else if (strcmp(argv[i], "--out-format") == 0 && i + 1 < argc) {
char* dup = str_dup(argv[++i]); char* dup = str_dup(argv[++i]);
if (!dup) return -1; if (!dup)
return -1;
free(config->out_format); free(config->out_format);
config->out_format = dup; config->out_format = dup;
} else if (strcmp(argv[i], "--info") == 0 && i + 1 < argc) { } else if (strcmp(argv[i], "--info") == 0 && i + 1 < argc) {
@@ -345,11 +346,13 @@ static int parse_args(Config* config, int argc, char* argv[], int* positional_ar
if (!config->filters) if (!config->filters)
config->filters = array_list_create(free); config->filters = array_list_create(free);
char* dup = str_dup(argv[++i]); char* dup = str_dup(argv[++i]);
if (!dup) return -1; if (!dup)
return -1;
array_list_add(config->filters, dup); array_list_add(config->filters, dup);
} else if (strcmp(argv[i], "--files-from") == 0 && i + 1 < argc) { } else if (strcmp(argv[i], "--files-from") == 0 && i + 1 < argc) {
char* dup = str_dup(argv[++i]); char* dup = str_dup(argv[++i]);
if (!dup) return -1; if (!dup)
return -1;
free(config->files_from); free(config->files_from);
config->files_from = dup; config->files_from = dup;
} else if (strcmp(argv[i], "--cvs-exclude") == 0) { } else if (strcmp(argv[i], "--cvs-exclude") == 0) {
@@ -361,7 +364,8 @@ static int parse_args(Config* config, int argc, char* argv[], int* positional_ar
} else if (strcmp(argv[i], "-e") == 0 || strcmp(argv[i], "--rsh") == 0) { } else if (strcmp(argv[i], "-e") == 0 || strcmp(argv[i], "--rsh") == 0) {
if (i + 1 < argc) { if (i + 1 < argc) {
char* dup = str_dup(argv[++i]); char* dup = str_dup(argv[++i]);
if (!dup) return -1; if (!dup)
return -1;
free(config->rsh_command); free(config->rsh_command);
config->rsh_command = dup; config->rsh_command = dup;
} else { } else {
@@ -370,27 +374,32 @@ static int parse_args(Config* config, int argc, char* argv[], int* positional_ar
} }
} else if (strcmp(argv[i], "--rsync-path") == 0 && i + 1 < argc) { } else if (strcmp(argv[i], "--rsync-path") == 0 && i + 1 < argc) {
char* dup = str_dup(argv[++i]); char* dup = str_dup(argv[++i]);
if (!dup) return -1; if (!dup)
return -1;
free(config->rsync_path); free(config->rsync_path);
config->rsync_path = dup; config->rsync_path = dup;
} else if (strcmp(argv[i], "--temp-dir") == 0 && i + 1 < argc) { } else if (strcmp(argv[i], "--temp-dir") == 0 && i + 1 < argc) {
char* dup = str_dup(argv[++i]); char* dup = str_dup(argv[++i]);
if (!dup) return -1; if (!dup)
return -1;
free(config->temp_dir); free(config->temp_dir);
config->temp_dir = dup; config->temp_dir = dup;
} else if (strcmp(argv[i], "--compare-dest") == 0 && i + 1 < argc) { } else if (strcmp(argv[i], "--compare-dest") == 0 && i + 1 < argc) {
char* dup = str_dup(argv[++i]); char* dup = str_dup(argv[++i]);
if (!dup) return -1; if (!dup)
return -1;
free(config->compare_dest); free(config->compare_dest);
config->compare_dest = dup; config->compare_dest = dup;
} else if (strcmp(argv[i], "--copy-dest") == 0 && i + 1 < argc) { } else if (strcmp(argv[i], "--copy-dest") == 0 && i + 1 < argc) {
char* dup = str_dup(argv[++i]); char* dup = str_dup(argv[++i]);
if (!dup) return -1; if (!dup)
return -1;
free(config->copy_dest); free(config->copy_dest);
config->copy_dest = dup; config->copy_dest = dup;
} else if (strcmp(argv[i], "--link-dest") == 0 && i + 1 < argc) { } else if (strcmp(argv[i], "--link-dest") == 0 && i + 1 < argc) {
char* dup = str_dup(argv[++i]); char* dup = str_dup(argv[++i]);
if (!dup) return -1; if (!dup)
return -1;
free(config->link_dest); free(config->link_dest);
config->link_dest = dup; config->link_dest = dup;
} else if (argv[i][0] == '-') { } else if (argv[i][0] == '-') {
+2 -3
View File
@@ -339,9 +339,8 @@ static int scan_directory_multithreaded(void* pipeline_context) {
context->config->send_directory, context->config->use_metadata, context->config->chunk_size, context->config->send_directory, context->config->use_metadata, context->config->chunk_size,
context->config->exclude_patterns, context->config->exclude_count, context->config->exclude_patterns, context->config->exclude_count,
context->config->include_patterns, context->config->include_count, context->config->max_size, context->config->include_patterns, context->config->include_count, context->config->max_size,
context->config->min_size, context->config->max_depth, 4, context->config->min_size, context->config->max_depth, 4, context->config->follow_symlinks,
context->config->follow_symlinks, context->config->copy_links, context->config->copy_links, context->config->safe_links, context->config->copy_unsafe_links);
context->config->safe_links, context->config->copy_unsafe_links);
Chunk* current_chunk; Chunk* current_chunk;
while ((current_chunk = parallel_scanner_next(scanner)) != NULL) { while ((current_chunk = parallel_scanner_next(scanner)) != NULL) {
+5 -5
View File
@@ -39,8 +39,8 @@ DirectoryScanner* directory_scanner_create(const char* root_directory, bool use_
int exclude_count, char** include_patterns, int exclude_count, char** include_patterns,
int include_count, unsigned long long max_size, int include_count, unsigned long long max_size,
unsigned long long min_size, int max_depth, unsigned long long min_size, int max_depth,
bool follow_symlinks, bool copy_links, bool follow_symlinks, bool copy_links, bool safe_links,
bool safe_links, bool copy_unsafe_links) { bool copy_unsafe_links) {
DirectoryScanner* scanner = malloc(sizeof(DirectoryScanner)); DirectoryScanner* scanner = malloc(sizeof(DirectoryScanner));
if (scanner == NULL) if (scanner == NULL)
return NULL; return NULL;
@@ -145,7 +145,8 @@ Chunk* directory_scanner_next(DirectoryScanner* scanner) {
} }
is_symlink = S_ISLNK(lstats.st_mode); is_symlink = S_ISLNK(lstats.st_mode);
if (is_symlink && !scanner->follow_symlinks && !scanner->copy_links && !scanner->safe_links && !scanner->copy_unsafe_links) { if (is_symlink && !scanner->follow_symlinks && !scanner->copy_links && !scanner->safe_links &&
!scanner->copy_unsafe_links) {
free(cur_path); free(cur_path);
continue; continue;
} }
@@ -310,8 +311,7 @@ ParallelScanner* parallel_scanner_create(char* root_directory, bool use_metadata
int exclude_count, char** include_patterns, int exclude_count, char** include_patterns,
int include_count, unsigned long long max_size, int include_count, unsigned long long max_size,
unsigned long long min_size, int max_depth, unsigned long long min_size, int max_depth,
int num_threads, int num_threads, bool follow_symlinks, bool copy_links,
bool follow_symlinks, bool copy_links,
bool safe_links, bool copy_unsafe_links) { bool safe_links, bool copy_unsafe_links) {
ParallelScanner* ps = calloc(1, sizeof(ParallelScanner)); ParallelScanner* ps = calloc(1, sizeof(ParallelScanner));
if (!ps) if (!ps)
+3 -4
View File
@@ -44,8 +44,8 @@ DirectoryScanner* directory_scanner_create(const char* root_directory, bool use_
int exclude_count, char** include_patterns, int exclude_count, char** include_patterns,
int include_count, unsigned long long max_size, int include_count, unsigned long long max_size,
unsigned long long min_size, int max_depth, unsigned long long min_size, int max_depth,
bool follow_symlinks, bool copy_links, bool follow_symlinks, bool copy_links, bool safe_links,
bool safe_links, bool copy_unsafe_links); bool copy_unsafe_links);
Chunk* directory_scanner_next(DirectoryScanner* scanner); Chunk* directory_scanner_next(DirectoryScanner* scanner);
void directory_scanner_destroy(DirectoryScanner* scanner); void directory_scanner_destroy(DirectoryScanner* scanner);
@@ -54,8 +54,7 @@ ParallelScanner* parallel_scanner_create(char* root_directory, bool use_metadata
int exclude_count, char** include_patterns, int exclude_count, char** include_patterns,
int include_count, unsigned long long max_size, int include_count, unsigned long long max_size,
unsigned long long min_size, int max_depth, unsigned long long min_size, int max_depth,
int num_threads, int num_threads, bool follow_symlinks, bool copy_links,
bool follow_symlinks, bool copy_links,
bool safe_links, bool copy_unsafe_links); bool safe_links, bool copy_unsafe_links);
Chunk* parallel_scanner_next(ParallelScanner* scanner); Chunk* parallel_scanner_next(ParallelScanner* scanner);
void parallel_scanner_destroy(ParallelScanner* scanner); void parallel_scanner_destroy(ParallelScanner* scanner);
-1
View File
@@ -89,7 +89,6 @@ Config* config_create(void) {
config->compare_dest = NULL; config->compare_dest = NULL;
config->copy_dest = NULL; config->copy_dest = NULL;
config->link_dest = NULL; config->link_dest = NULL;
>>>>>>> origin/fix/rsync-parity-all
return config; return config;
} }
+2 -1
View File
@@ -183,7 +183,8 @@ bool file_save_to_disk(const char* root_directory, File* file, const Config* con
size_t root_len = strlen(resolved_root); size_t root_len = strlen(resolved_root);
if (strncmp(resolved_dir, resolved_root, root_len) != 0 || if (strncmp(resolved_dir, resolved_root, root_len) != 0 ||
(resolved_dir[root_len] != '\0' && resolved_dir[root_len] != '/')) { (resolved_dir[root_len] != '\0' && resolved_dir[root_len] != '/')) {
log_message(LOG_LEVEL_ERROR, "Path escape detected: %s is outside %s", disk_path, root_directory); log_message(LOG_LEVEL_ERROR, "Path escape detected: %s is outside %s", disk_path,
root_directory);
free(resolved_dir); free(resolved_dir);
free(resolved_root); free(resolved_root);
free(disk_path); free(disk_path);
+6 -6
View File
@@ -48,8 +48,8 @@ static void test_config_lifecycle() {
} }
static void test_config_ssh_dest() { static void test_config_ssh_dest() {
Config* cfg = make_config("1.0", "/src", "user@host:/dst", true, false, false, false, false, 1, Config* cfg =
false, 0); make_config("1.0", "/src", "user@host:/dst", true, false, false, false, false, 1, false, 0);
EXPECT_NOT_NULL(cfg); EXPECT_NOT_NULL(cfg);
EXPECT_EQ_INT(cfg->transport, TRANSPORT_TCP); EXPECT_EQ_INT(cfg->transport, TRANSPORT_TCP);
EXPECT_NULL(cfg->ssh_destination); EXPECT_NULL(cfg->ssh_destination);
@@ -63,8 +63,8 @@ static void test_config_ssh_dest() {
} }
static void test_config_ssh_dest_local_path() { static void test_config_ssh_dest_local_path() {
Config* cfg = make_config("1.0", "/src", "/local/path", true, false, false, false, false, 1, Config* cfg =
false, 0); make_config("1.0", "/src", "/local/path", true, false, false, false, false, 1, false, 0);
config_parse_ssh_dest(cfg); config_parse_ssh_dest(cfg);
EXPECT_EQ_INT(cfg->transport, TRANSPORT_TCP); EXPECT_EQ_INT(cfg->transport, TRANSPORT_TCP);
EXPECT_NULL(cfg->ssh_destination); EXPECT_NULL(cfg->ssh_destination);
@@ -73,8 +73,8 @@ static void test_config_ssh_dest_local_path() {
} }
static void test_config_ssh_dest_no_user() { static void test_config_ssh_dest_no_user() {
Config* cfg = make_config("1.0", "/src", "host:/remote", true, false, false, false, false, 1, Config* cfg =
false, 0); make_config("1.0", "/src", "host:/remote", true, false, false, false, false, 1, false, 0);
config_parse_ssh_dest(cfg); config_parse_ssh_dest(cfg);
EXPECT_EQ_INT(cfg->transport, TRANSPORT_SSH); EXPECT_EQ_INT(cfg->transport, TRANSPORT_SSH);
EXPECT_EQ_STR(cfg->ssh_destination, "host:/remote"); EXPECT_EQ_STR(cfg->ssh_destination, "host:/remote");
+24 -24
View File
@@ -18,8 +18,8 @@ static void test_scanner_single_file() {
EXPECT_EQ_INT(mkdir(dir, 0755), 0); EXPECT_EQ_INT(mkdir(dir, 0755), 0);
create_test_file(file1, content1); create_test_file(file1, content1);
DirectoryScanner* scanner = DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 0, 0,
directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 0, 0, 0, false, false, false, false); 0, false, false, false, false);
EXPECT_NOT_NULL(scanner); EXPECT_NOT_NULL(scanner);
Chunk* chunk = directory_scanner_next(scanner); Chunk* chunk = directory_scanner_next(scanner);
@@ -47,8 +47,8 @@ static void test_scanner_multiple_files() {
create_test_file(file1, content1); create_test_file(file1, content1);
create_test_file(file2, content2); create_test_file(file2, content2);
DirectoryScanner* scanner = DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 0, 0,
directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 0, 0, 0, false, false, false, false); 0, false, false, false, false);
EXPECT_NOT_NULL(scanner); EXPECT_NOT_NULL(scanner);
const Chunk* chunk = directory_scanner_next(scanner); const Chunk* chunk = directory_scanner_next(scanner);
@@ -87,8 +87,8 @@ static void test_scanner_subdirectory() {
create_test_file(root_file, content); create_test_file(root_file, content);
create_test_file(sub_file, content); create_test_file(sub_file, content);
DirectoryScanner* scanner = DirectoryScanner* scanner = directory_scanner_create((char*)root, false, 0, NULL, 0, NULL, 0, 0,
directory_scanner_create((char*)root, false, 0, NULL, 0, NULL, 0, 0, 0, 0, false, false, false, false); 0, 0, false, false, false, false);
EXPECT_NOT_NULL(scanner); EXPECT_NOT_NULL(scanner);
int total_files = 0; int total_files = 0;
@@ -111,8 +111,8 @@ static void test_scanner_empty_directory() {
EXPECT_EQ_INT(mkdir(dir, 0755), 0); EXPECT_EQ_INT(mkdir(dir, 0755), 0);
DirectoryScanner* scanner = DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 0, 0,
directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 0, 0, 0, false, false, false, false); 0, false, false, false, false);
EXPECT_NOT_NULL(scanner); EXPECT_NOT_NULL(scanner);
const Chunk* chunk = directory_scanner_next(scanner); const Chunk* chunk = directory_scanner_next(scanner);
@@ -135,8 +135,8 @@ static void test_scanner_exclude_pattern() {
create_test_file(f_tmp, content); create_test_file(f_tmp, content);
char* exclude[] = {"*.tmp"}; char* exclude[] = {"*.tmp"};
DirectoryScanner* scanner = DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, exclude, 1, NULL, 0, 0,
directory_scanner_create((char*)dir, false, 0, exclude, 1, NULL, 0, 0, 0, 0, false, false, false, false); 0, 0, false, false, false, false);
EXPECT_NOT_NULL(scanner); EXPECT_NOT_NULL(scanner);
Chunk* chunk = directory_scanner_next(scanner); Chunk* chunk = directory_scanner_next(scanner);
@@ -168,8 +168,8 @@ static void test_scanner_exclude_subdirectory() {
create_test_file(sub_tmp, content); create_test_file(sub_tmp, content);
char* exclude[] = {"*.tmp"}; char* exclude[] = {"*.tmp"};
DirectoryScanner* scanner = DirectoryScanner* scanner = directory_scanner_create((char*)root, false, 0, exclude, 1, NULL, 0,
directory_scanner_create((char*)root, false, 0, exclude, 1, NULL, 0, 0, 0, 0, false, false, false, false); 0, 0, 0, false, false, false, false);
EXPECT_NOT_NULL(scanner); EXPECT_NOT_NULL(scanner);
int total = 0; int total = 0;
@@ -206,8 +206,8 @@ static void test_scanner_include_and_exclude() {
char* exclude[] = {"*.bak"}; char* exclude[] = {"*.bak"};
char* include[] = {"*.txt", "*.log"}; char* include[] = {"*.txt", "*.log"};
DirectoryScanner* scanner = DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, exclude, 1, include, 2,
directory_scanner_create((char*)dir, false, 0, exclude, 1, include, 2, 0, 0, 0, false, false, false, false); 0, 0, 0, false, false, false, false);
EXPECT_NOT_NULL(scanner); EXPECT_NOT_NULL(scanner);
Chunk* chunk = directory_scanner_next(scanner); Chunk* chunk = directory_scanner_next(scanner);
@@ -243,8 +243,8 @@ static void test_scanner_max_size() {
create_test_file(large, "this_content_is_longer_than_ten_chars"); create_test_file(large, "this_content_is_longer_than_ten_chars");
/* max_size = 10 — only files <= 10 bytes */ /* max_size = 10 — only files <= 10 bytes */
DirectoryScanner* scanner = DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 10,
directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 10, 0, 0, false, false, false, false); 0, 0, false, false, false, false);
EXPECT_NOT_NULL(scanner); EXPECT_NOT_NULL(scanner);
Chunk* chunk = directory_scanner_next(scanner); Chunk* chunk = directory_scanner_next(scanner);
@@ -271,8 +271,8 @@ static void test_scanner_min_size() {
create_test_file(data_f, "some content here"); create_test_file(data_f, "some content here");
/* min_size = 1 — only files >= 1 byte */ /* min_size = 1 — only files >= 1 byte */
DirectoryScanner* scanner = DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 0, 1,
directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 0, 1, 0, false, false, false, false); 0, false, false, false, false);
EXPECT_NOT_NULL(scanner); EXPECT_NOT_NULL(scanner);
Chunk* chunk = directory_scanner_next(scanner); Chunk* chunk = directory_scanner_next(scanner);
@@ -301,8 +301,8 @@ static void test_scanner_size_range() {
create_test_file(huge, "this is a much larger file for testing size filters"); create_test_file(huge, "this is a much larger file for testing size filters");
/* Only files between 3 and 20 bytes */ /* Only files between 3 and 20 bytes */
DirectoryScanner* scanner = DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 20,
directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 20, 3, 0, false, false, false, false); 3, 0, false, false, false, false);
EXPECT_NOT_NULL(scanner); EXPECT_NOT_NULL(scanner);
Chunk* chunk = directory_scanner_next(scanner); Chunk* chunk = directory_scanner_next(scanner);
@@ -337,8 +337,8 @@ static void test_scanner_mixed_patterns() {
/* Exclude *.bak, include *.txt, min_size=3, max_size=10 */ /* Exclude *.bak, include *.txt, min_size=3, max_size=10 */
char* exclude[] = {"*.bak"}; char* exclude[] = {"*.bak"};
char* include[] = {"*.txt"}; char* include[] = {"*.txt"};
DirectoryScanner* scanner = DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, exclude, 1, include, 1,
directory_scanner_create((char*)dir, false, 0, exclude, 1, include, 1, 10, 3, 0, false, false, false, false); 10, 3, 0, false, false, false, false);
EXPECT_NOT_NULL(scanner); EXPECT_NOT_NULL(scanner);
Chunk* chunk = directory_scanner_next(scanner); Chunk* chunk = directory_scanner_next(scanner);
@@ -368,8 +368,8 @@ static void test_scanner_no_patterns() {
create_test_file(f1, "first"); create_test_file(f1, "first");
create_test_file(f2, "second"); create_test_file(f2, "second");
DirectoryScanner* scanner = DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 0, 0,
directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 0, 0, 0, false, false, false, false); 0, false, false, false, false);
EXPECT_NOT_NULL(scanner); EXPECT_NOT_NULL(scanner);
Chunk* chunk = directory_scanner_next(scanner); Chunk* chunk = directory_scanner_next(scanner);