From 415adf2077265d6b5cdcd7c304f5b40c532ad24b Mon Sep 17 00:00:00 2001 From: TapTap Date: Tue, 21 Jul 2026 18:01:02 +0200 Subject: [PATCH] Merge all 5 PRs: security, CLI features, protocol, performance, tests/docs --- src/client/client_send.c | 8 ++++---- src/client/scanner.c | 7 +++++-- src/client/scanner.h | 9 ++++++--- src/shared/file.h | 2 ++ src/shared/log.c | 2 +- src/shared/utils.c | 34 +++++++++++++++++++++++++++------- tests/test_file.c | 4 ---- tests/test_file_sendfile.c | 4 ---- tests/test_scanner.c | 16 ++++++++-------- 9 files changed, 53 insertions(+), 33 deletions(-) diff --git a/src/client/client_send.c b/src/client/client_send.c index a610c0d..7f38741 100644 --- a/src/client/client_send.c +++ b/src/client/client_send.c @@ -305,7 +305,7 @@ static int scan_directory_multithreaded(void* pipeline_context) { context->config->send_directory, context->config->use_metadata, context->config->chunk_size, context->config->exclude_patterns, context->config->exclude_count, context->config->include_patterns, context->config->include_count, context->config->max_size, - context->config->min_size, 4); + context->config->min_size, context->config->max_depth, 4); Chunk* current_chunk; while ((current_chunk = parallel_scanner_next(scanner)) != NULL) { @@ -368,7 +368,7 @@ int send_files(Config* config) { DirectoryScanner* scanner = directory_scanner_create( config->send_directory, config->use_metadata, config->chunk_size, config->exclude_patterns, config->exclude_count, config->include_patterns, config->include_count, config->max_size, - config->min_size); + config->min_size, config->max_depth); Chunk* chunk; int file_count = 0; unsigned long long total_bytes = 0; @@ -421,7 +421,7 @@ int send_files(Config* config) { DirectoryScanner* scanner = directory_scanner_create( config->send_directory, config->use_metadata, config->chunk_size, config->exclude_patterns, config->exclude_count, config->include_patterns, config->include_count, config->max_size, - config->min_size); + config->min_size, config->max_depth); Chunk* current_chunk; unsigned long long total_bytes = 0; time_t last_progress = 0; @@ -510,7 +510,7 @@ int send_files_multithreaded(Config* config) { DirectoryScanner* scanner = directory_scanner_create( config->send_directory, config->use_metadata, config->chunk_size, config->exclude_patterns, config->exclude_count, config->include_patterns, config->include_count, config->max_size, - config->min_size); + config->min_size, config->max_depth); Chunk* chunk; int file_count = 0; unsigned long long total_bytes = 0; diff --git a/src/client/scanner.c b/src/client/scanner.c index ee194c3..7828e4e 100644 --- a/src/client/scanner.c +++ b/src/client/scanner.c @@ -215,6 +215,7 @@ typedef struct { int include_count; unsigned long long max_size; unsigned long long min_size; + int max_depth; } ParallelWorkerArg; static int parallel_worker_thread(void* arg) { @@ -222,7 +223,7 @@ static int parallel_worker_thread(void* arg) { for (int i = 0; i < wa->dir_count; i++) { DirectoryScanner* ds = directory_scanner_create( wa->dirs[i], wa->use_metadata, wa->chunk_size, wa->exclude_patterns, wa->exclude_count, - wa->include_patterns, wa->include_count, wa->max_size, wa->min_size); + wa->include_patterns, wa->include_count, wa->max_size, wa->min_size, wa->max_depth); Chunk* chunk; while ((chunk = directory_scanner_next(ds)) != NULL) { queue_enqueue_multithreaded(wa->ps->result_queue, chunk, &wa->ps->result_mutex, @@ -248,7 +249,8 @@ ParallelScanner* parallel_scanner_create(char* root_directory, bool use_metadata unsigned long long chunk_size, char** exclude_patterns, int exclude_count, char** include_patterns, int include_count, unsigned long long max_size, - unsigned long long min_size, int num_threads) { + unsigned long long min_size, int max_depth, + int num_threads) { ParallelScanner* ps = calloc(1, sizeof(ParallelScanner)); if (!ps) return NULL; @@ -406,6 +408,7 @@ ParallelScanner* parallel_scanner_create(char* root_directory, bool use_metadata wa->include_count = include_count; wa->max_size = max_size; wa->min_size = min_size; + wa->max_depth = max_depth; start += count; if (thrd_create(&ps->threads[t], parallel_worker_thread, wa) != thrd_success) { for (int j = 0; j < count; j++) diff --git a/src/client/scanner.h b/src/client/scanner.h index c6958fe..1a8c4dd 100644 --- a/src/client/scanner.h +++ b/src/client/scanner.h @@ -19,6 +19,8 @@ typedef struct { int include_count; unsigned long long max_size; unsigned long long min_size; + int max_depth; + int current_depth; } DirectoryScanner; typedef struct { @@ -33,11 +35,11 @@ typedef struct { Chunk* initial_chunk; } ParallelScanner; -DirectoryScanner* directory_scanner_create(char* root_directory, bool use_metadata, +DirectoryScanner* directory_scanner_create(const char* root_directory, bool use_metadata, unsigned long long chunk_size, char** exclude_patterns, int exclude_count, char** include_patterns, int include_count, unsigned long long max_size, - unsigned long long min_size); + unsigned long long min_size, int max_depth); Chunk* directory_scanner_next(DirectoryScanner* scanner); void directory_scanner_destroy(DirectoryScanner* scanner); @@ -45,7 +47,8 @@ ParallelScanner* parallel_scanner_create(char* root_directory, bool use_metadata unsigned long long chunk_size, char** exclude_patterns, int exclude_count, char** include_patterns, int include_count, unsigned long long max_size, - unsigned long long min_size, int num_threads); + unsigned long long min_size, int max_depth, + int num_threads); Chunk* parallel_scanner_next(ParallelScanner* scanner); void parallel_scanner_destroy(ParallelScanner* scanner); diff --git a/src/shared/file.h b/src/shared/file.h index 2fffeea..e3e514b 100644 --- a/src/shared/file.h +++ b/src/shared/file.h @@ -6,6 +6,8 @@ #include #include +typedef enum { FILE_TYPE_REGULAR, FILE_TYPE_SYMLINK, FILE_TYPE_DIR } FileType; + typedef struct { mode_t mode; uid_t uid; diff --git a/src/shared/log.c b/src/shared/log.c index 3f91161..07a5d27 100644 --- a/src/shared/log.c +++ b/src/shared/log.c @@ -15,7 +15,7 @@ void log_set_file(FILE* fp) { log_fp = fp; } -void log_message(LogLevel log_level, char* format, ...) { +void log_message(LogLevel log_level, const char* format, ...) { if (log_level < current_log_level) return; time_t now = time(NULL); diff --git a/src/shared/utils.c b/src/shared/utils.c index 6ff5d99..e88d563 100644 --- a/src/shared/utils.c +++ b/src/shared/utils.c @@ -61,6 +61,19 @@ char* str_dup(const char* string) { bool glob_match(const char* pattern, const char* str) { while (*pattern) { if (*pattern == '*') { + if (*(pattern + 1) == '*') { + pattern += 2; + if (*pattern == '\0') + return true; + if (*pattern == '/') + pattern++; + while (*str) { + if (glob_match(pattern, str)) + return true; + str++; + } + return glob_match(pattern, str); + } pattern++; while (*str && *str != '/') { if (glob_match(pattern, str)) @@ -74,8 +87,15 @@ bool glob_match(const char* pattern, const char* str) { pattern++; str++; } else { - if (*pattern != *str) + if (*pattern != *str) { + if (*pattern == '/' && *(pattern + 1) == '*' && *(pattern + 2) == '*') { + const char* rest = pattern + 3; + if (*rest == '/') + rest++; + return glob_match(rest, str); + } return false; + } pattern++; str++; } @@ -168,18 +188,18 @@ bool has_path_traversal(const char* path) { return false; } -char* path_cat(const char* path1, char* path2) { +char* path_cat(const char* path1, const char* path2) { if (path1 == NULL || *path1 == '\0') return str_dup(path2); if (path2 == NULL || *path2 == '\0') return str_dup(path1); - int path1_len = strlen(path1); - int path2_len = strlen(path2); - char* path2_pointer = path2; + size_t path1_len = strlen(path1); + size_t path2_len = strlen(path2); + size_t offset = 0; if (path1[path1_len - 1] == '/') path1_len -= 1; if (path2[0] == '/') { - path2_pointer += 1; + offset = 1; path2_len -= 1; } char* new_path = malloc(path1_len + path2_len + 2); @@ -187,7 +207,7 @@ char* path_cat(const char* path1, char* path2) { return NULL; memcpy(new_path, path1, path1_len); new_path[path1_len] = '/'; - memcpy(new_path + path1_len + 1, path2_pointer, path2_len); + memcpy(new_path + path1_len + 1, path2 + offset, path2_len); new_path[path1_len + path2_len + 1] = '\0'; return new_path; } diff --git a/tests/test_file.c b/tests/test_file.c index a1eae0d..25862a5 100644 --- a/tests/test_file.c +++ b/tests/test_file.c @@ -217,10 +217,6 @@ static void test_file_send_no_path() { pid_t pid = fork(); if (pid == 0) { close(p[1]); - // Read file type indicator - int file_type; - EXPECT_TRUE(receive_int(p[0], &file_type)); - EXPECT_EQ_INT(file_type, (int)FILE_TYPE_REGULAR); Data* received = receive_data(p[0]); close(p[0]); diff --git a/tests/test_file_sendfile.c b/tests/test_file_sendfile.c index 6bb4dcd..86119e4 100644 --- a/tests/test_file_sendfile.c +++ b/tests/test_file_sendfile.c @@ -224,10 +224,6 @@ static void test_sendfile_no_path() { pid_t pid = fork(); if (pid == 0) { close(p[1]); - /* When send_path is false, the sender still sends file_type + data */ - int file_type; - EXPECT_TRUE(receive_int(p[0], &file_type)); - EXPECT_EQ_INT(file_type, (int)FILE_TYPE_REGULAR); Data* received = receive_data(p[0]); close(p[0]); diff --git a/tests/test_scanner.c b/tests/test_scanner.c index 46f7090..903693e 100644 --- a/tests/test_scanner.c +++ b/tests/test_scanner.c @@ -136,7 +136,7 @@ static void test_scanner_exclude_pattern() { char* exclude[] = {"*.tmp"}; DirectoryScanner* scanner = - directory_scanner_create((char*)dir, false, 0, exclude, 1, NULL, 0, 0, 0); + directory_scanner_create((char*)dir, false, 0, exclude, 1, NULL, 0, 0, 0, 0); EXPECT_NOT_NULL(scanner); Chunk* chunk = directory_scanner_next(scanner); @@ -169,7 +169,7 @@ static void test_scanner_exclude_subdirectory() { char* exclude[] = {"*.tmp"}; DirectoryScanner* scanner = - directory_scanner_create((char*)root, false, 0, exclude, 1, NULL, 0, 0, 0); + directory_scanner_create((char*)root, false, 0, exclude, 1, NULL, 0, 0, 0, 0); EXPECT_NOT_NULL(scanner); int total = 0; @@ -207,7 +207,7 @@ static void test_scanner_include_and_exclude() { char* exclude[] = {"*.bak"}; char* include[] = {"*.txt", "*.log"}; DirectoryScanner* scanner = - directory_scanner_create((char*)dir, false, 0, exclude, 1, include, 2, 0, 0); + directory_scanner_create((char*)dir, false, 0, exclude, 1, include, 2, 0, 0, 0); EXPECT_NOT_NULL(scanner); Chunk* chunk = directory_scanner_next(scanner); @@ -244,7 +244,7 @@ static void test_scanner_max_size() { /* max_size = 10 — only files <= 10 bytes */ DirectoryScanner* scanner = - directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 10, 0); + directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 10, 0, 0); EXPECT_NOT_NULL(scanner); Chunk* chunk = directory_scanner_next(scanner); @@ -272,7 +272,7 @@ static void test_scanner_min_size() { /* min_size = 1 — only files >= 1 byte */ 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); EXPECT_NOT_NULL(scanner); Chunk* chunk = directory_scanner_next(scanner); @@ -302,7 +302,7 @@ static void test_scanner_size_range() { /* Only files between 3 and 20 bytes */ DirectoryScanner* scanner = - directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 20, 3); + directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 20, 3, 0); EXPECT_NOT_NULL(scanner); Chunk* chunk = directory_scanner_next(scanner); @@ -338,7 +338,7 @@ static void test_scanner_mixed_patterns() { char* exclude[] = {"*.bak"}; char* include[] = {"*.txt"}; DirectoryScanner* scanner = - directory_scanner_create((char*)dir, false, 0, exclude, 1, include, 1, 10, 3); + directory_scanner_create((char*)dir, false, 0, exclude, 1, include, 1, 10, 3, 0); EXPECT_NOT_NULL(scanner); Chunk* chunk = directory_scanner_next(scanner); @@ -369,7 +369,7 @@ static void test_scanner_no_patterns() { create_test_file(f2, "second"); 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); EXPECT_NOT_NULL(scanner); Chunk* chunk = directory_scanner_next(scanner);