Compare commits

..

11 Commits

Author SHA1 Message Date
TapTap 31da8bf081 fix: address review findings — localtime_r, test_scanner cleanup
CI / lint (pull_request) Successful in 8s
CI / sanitizers (address) (pull_request) Successful in 15s
CI / sanitizers (undefined) (pull_request) Successful in 14s
CI / coverage (pull_request) Successful in 10s
CI / fuzz-build (pull_request) Successful in 13s
CI / valgrind (pull_request) Successful in 12s
CI / build-and-test (pull_request) Successful in 54s
2026-07-21 14:15:37 +02:00
TapTap 925760d1bd fix: address review findings — localtime_r, test_scanner cleanup
CI / lint (pull_request) Successful in 8s
CI / sanitizers (address) (pull_request) Successful in 14s
CI / sanitizers (undefined) (pull_request) Successful in 15s
CI / fuzz-build (pull_request) Successful in 14s
CI / coverage (pull_request) Successful in 9s
CI / valgrind (pull_request) Successful in 12s
CI / build-and-test (pull_request) Successful in 54s
2026-07-21 14:14:25 +02:00
TapTap 552561146a fix: clang-format compliance
CI / lint (pull_request) Successful in 8s
CI / sanitizers (address) (pull_request) Successful in 14s
CI / sanitizers (undefined) (pull_request) Successful in 16s
CI / fuzz-build (pull_request) Successful in 15s
CI / coverage (pull_request) Successful in 9s
CI / valgrind (pull_request) Successful in 11s
CI / build-and-test (pull_request) Successful in 52s
2026-07-20 22:01:03 +02:00
TapTap 9a214c46e2 fix: memory safety — malloc NULL checks, strcpy→memcpy
CI / lint (pull_request) Failing after 2s
CI / build-and-test (pull_request) Has been skipped
CI / sanitizers (address) (pull_request) Has been skipped
CI / sanitizers (undefined) (pull_request) Has been skipped
CI / fuzz-build (pull_request) Has been skipped
CI / coverage (pull_request) Has been skipped
CI / valgrind (pull_request) Has been skipped
2026-07-20 21:24:44 +02:00
TapTap 8234677276 fix: auto-detect valgrind to skip fork tests
CI / lint (pull_request) Successful in 8s
CI / sanitizers (address) (pull_request) Successful in 15s
CI / sanitizers (undefined) (pull_request) Successful in 15s
CI / coverage (pull_request) Successful in 9s
CI / fuzz-build (pull_request) Successful in 12s
CI / valgrind (pull_request) Successful in 12s
CI / build-and-test (pull_request) Successful in 54s
2026-07-20 20:51:04 +02:00
TapTap 744ac8e40c ci: re-trigger after cppcheck fixes
CI / lint (pull_request) Successful in 8s
CI / sanitizers (address) (pull_request) Successful in 14s
CI / sanitizers (undefined) (pull_request) Successful in 14s
CI / fuzz-build (pull_request) Successful in 14s
CI / coverage (pull_request) Successful in 8s
CI / valgrind (pull_request) Successful in 11s
CI / build-and-test (pull_request) Successful in 54s
2026-07-20 20:41:17 +02:00
TapTap f486d34b16 ci: re-trigger after fixes
CI / lint (pull_request) Successful in 8s
CI / sanitizers (address) (pull_request) Successful in 15s
CI / sanitizers (undefined) (pull_request) Successful in 16s
CI / fuzz-build (pull_request) Successful in 14s
CI / coverage (pull_request) Successful in 9s
CI / valgrind (pull_request) Successful in 12s
CI / build-and-test (pull_request) Successful in 1m8s
2026-07-20 20:28:17 +02:00
TapTap eef272fa4e ci: re-trigger after review fixes
CI / lint (pull_request) Successful in 8s
CI / sanitizers (address) (pull_request) Successful in 14s
CI / sanitizers (undefined) (pull_request) Successful in 13s
CI / fuzz-build (pull_request) Successful in 11s
CI / build-and-test (pull_request) Successful in 54s
CI / coverage (pull_request) Successful in 9s
CI / valgrind (pull_request) Successful in 12s
2026-07-20 20:11:24 +02:00
TapTap 27e3ac11db fix: bump protocol version, add static_assert for metadata sizes
CI / lint (pull_request) Successful in 8s
CI / sanitizers (address) (pull_request) Successful in 14s
CI / sanitizers (undefined) (pull_request) Successful in 14s
CI / fuzz-build (pull_request) Successful in 12s
CI / coverage (pull_request) Successful in 9s
CI / build-and-test (pull_request) Successful in 55s
CI / valgrind (pull_request) Successful in 11s
2026-07-20 19:53:03 +02:00
TapTap 86247fe2b5 ci: trigger CI on PR
CI / lint (pull_request) Successful in 8s
CI / sanitizers (address) (pull_request) Successful in 14s
CI / sanitizers (undefined) (pull_request) Successful in 14s
CI / fuzz-build (pull_request) Successful in 12s
CI / coverage (pull_request) Successful in 9s
CI / build-and-test (pull_request) Successful in 54s
CI / valgrind (pull_request) Successful in 11s
2026-07-20 19:48:32 +02:00
TapTap d75701270d fix: refactoring and portability — issues #61, #51, #52
CI / lint (pull_request) Successful in 8s
CI / sanitizers (address) (pull_request) Successful in 14s
CI / sanitizers (undefined) (pull_request) Successful in 13s
CI / fuzz-build (pull_request) Successful in 12s
CI / coverage (pull_request) Successful in 9s
CI / build-and-test (pull_request) Successful in 54s
CI / valgrind (pull_request) Successful in 11s
2026-07-20 19:38:45 +02:00
19 changed files with 169 additions and 203 deletions
+4
View File
@@ -56,6 +56,7 @@ static void print_usage(void) {
printf(" --key <path> TLS private key file (PEM)\n"); printf(" --key <path> TLS private key file (PEM)\n");
printf(" --ca <path> TLS CA certificate file (PEM)\n"); printf(" --ca <path> TLS CA certificate file (PEM)\n");
printf(" --help Show this help\n"); printf(" --help Show this help\n");
printf(" -V, --version Show version and exit\n");
} }
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
@@ -80,6 +81,9 @@ int main(int argc, char* argv[]) {
if (strcmp(argv[i], "--help") == 0) { if (strcmp(argv[i], "--help") == 0) {
print_usage(); print_usage();
goto cleanup; goto cleanup;
} else if (strcmp(argv[i], "-V") == 0 || strcmp(argv[i], "--version") == 0) {
printf("fastsync version %s\n", PROTOCOL_VERSION);
goto cleanup;
} else if (strcmp(argv[i], "-a") == 0 || strcmp(argv[i], "--archive") == 0) { } else if (strcmp(argv[i], "-a") == 0 || strcmp(argv[i], "--archive") == 0) {
config->use_compression = true; config->use_compression = true;
config->use_multithreading = true; config->use_multithreading = true;
+3 -58
View File
@@ -24,58 +24,9 @@ DirectoryScanner* directory_scanner_create(char* root_directory, bool use_metada
scanner->current_path = NULL; scanner->current_path = NULL;
scanner->use_metadata = use_metadata; scanner->use_metadata = use_metadata;
scanner->chunk_size = chunk_size > 0 ? chunk_size : DESIRED_CHUNK_SIZE; scanner->chunk_size = chunk_size > 0 ? chunk_size : DESIRED_CHUNK_SIZE;
/* Deep-copy exclude patterns */ scanner->exclude_patterns = exclude_patterns;
if (exclude_count > 0 && exclude_patterns != NULL) {
scanner->exclude_patterns = malloc((size_t)exclude_count * sizeof(char*));
if (scanner->exclude_patterns == NULL) {
queue_destroy(scanner->directories);
free(scanner);
return NULL;
}
for (int i = 0; i < exclude_count; i++) {
scanner->exclude_patterns[i] = str_dup(exclude_patterns[i]);
if (scanner->exclude_patterns[i] == NULL) {
for (int j = 0; j < i; j++)
free(scanner->exclude_patterns[j]);
free(scanner->exclude_patterns);
queue_destroy(scanner->directories);
free(scanner);
return NULL;
}
}
} else {
scanner->exclude_patterns = NULL;
}
scanner->exclude_count = exclude_count; scanner->exclude_count = exclude_count;
scanner->include_patterns = include_patterns;
/* Deep-copy include patterns */
if (include_count > 0 && include_patterns != NULL) {
scanner->include_patterns = malloc((size_t)include_count * sizeof(char*));
if (scanner->include_patterns == NULL) {
for (int i = 0; i < exclude_count; i++)
free(scanner->exclude_patterns[i]);
free(scanner->exclude_patterns);
queue_destroy(scanner->directories);
free(scanner);
return NULL;
}
for (int i = 0; i < include_count; i++) {
scanner->include_patterns[i] = str_dup(include_patterns[i]);
if (scanner->include_patterns[i] == NULL) {
for (int j = 0; j < i; j++)
free(scanner->include_patterns[j]);
free(scanner->include_patterns);
for (int j = 0; j < exclude_count; j++)
free(scanner->exclude_patterns[j]);
free(scanner->exclude_patterns);
queue_destroy(scanner->directories);
free(scanner);
return NULL;
}
}
} else {
scanner->include_patterns = NULL;
}
scanner->include_count = include_count; scanner->include_count = include_count;
scanner->max_size = max_size; scanner->max_size = max_size;
scanner->min_size = min_size; scanner->min_size = min_size;
@@ -91,12 +42,6 @@ void directory_scanner_destroy(DirectoryScanner* scanner) {
scanner->current_dir = NULL; scanner->current_dir = NULL;
} }
free(scanner->current_path); free(scanner->current_path);
for (int i = 0; i < scanner->exclude_count; i++)
free(scanner->exclude_patterns[i]);
free(scanner->exclude_patterns);
for (int i = 0; i < scanner->include_count; i++)
free(scanner->include_patterns[i]);
free(scanner->include_patterns);
queue_destroy(scanner->directories); queue_destroy(scanner->directories);
free(scanner); free(scanner);
} }
@@ -159,7 +104,7 @@ Chunk* directory_scanner_next(DirectoryScanner* scanner) {
char* cur_path = path_cat(scanner->current_path, entry->d_name); char* cur_path = path_cat(scanner->current_path, entry->d_name);
struct stat stats; struct stat stats;
if (lstat(cur_path, &stats) != 0) { if (stat(cur_path, &stats) != 0) {
free(cur_path); free(cur_path);
continue; continue;
} }
+4
View File
@@ -135,6 +135,7 @@ static void print_server_usage(void) {
printf(" --ca <path> TLS CA certificate file (PEM)\n"); printf(" --ca <path> TLS CA certificate file (PEM)\n");
printf(" -v, --verbose Enable debug logging\n"); printf(" -v, --verbose Enable debug logging\n");
printf(" --help Show this help\n"); printf(" --help Show this help\n");
printf(" -V, --version Show version and exit\n");
} }
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
@@ -149,6 +150,9 @@ int main(int argc, char* argv[]) {
if (strcmp(argv[i], "--help") == 0) { if (strcmp(argv[i], "--help") == 0) {
print_server_usage(); print_server_usage();
return 0; return 0;
} else if (strcmp(argv[i], "-V") == 0 || strcmp(argv[i], "--version") == 0) {
printf("fastsync-server version %s\n", PROTOCOL_VERSION);
return 0;
} else if (strcmp(argv[i], "--stdio") == 0) { } else if (strcmp(argv[i], "--stdio") == 0) {
io_set_fds(STDIN_FILENO, STDOUT_FILENO); io_set_fds(STDIN_FILENO, STDOUT_FILENO);
handler(STDIN_FILENO); handler(STDIN_FILENO);
+3 -12
View File
@@ -1,8 +1,7 @@
#include "compression.h" #include "compression.h"
#include "data.h" #include "data.h"
#include "log.h" #include "log.h"
#include <stdint.h> #include "stdlib.h"
#include <stdlib.h>
#include "zstd.h" #include "zstd.h"
#define INITIAL_DECOMPRESS_BUF_SIZE (1024 * 1024) #define INITIAL_DECOMPRESS_BUF_SIZE (1024 * 1024)
@@ -67,16 +66,8 @@ Data* data_decompress(Data* compressed_data) {
return NULL; return NULL;
} }
size_t buf_size = INITIAL_DECOMPRESS_BUF_SIZE; size_t buf_size =
if (!ZSTD_isError(dst_size) && dst_size > 0) { (!ZSTD_isError(dst_size) && dst_size > 0) ? (size_t)dst_size : INITIAL_DECOMPRESS_BUF_SIZE;
if (dst_size > SIZE_MAX) {
log_message(LOG_LEVEL_ERROR,
"Decompressed size %llu exceeds addressable memory, using fallback buffer",
dst_size);
} else {
buf_size = (size_t)dst_size;
}
}
Data* uncompressed_data = data_create_empty(buf_size); Data* uncompressed_data = data_create_empty(buf_size);
if (!uncompressed_data) { if (!uncompressed_data) {
log_message(LOG_LEVEL_ERROR, "Failed to allocate decompression buffer"); log_message(LOG_LEVEL_ERROR, "Failed to allocate decompression buffer");
+2
View File
@@ -14,6 +14,8 @@ Config* config_create(char* version, char* send_directory, char* receive_directo
bool use_sendfile, unsigned long long chunk_size) { bool use_sendfile, unsigned long long chunk_size) {
Config* config = malloc(sizeof(Config)); Config* config = malloc(sizeof(Config));
if (config == NULL)
return NULL;
config->version = version; config->version = version;
config->send_directory = send_directory; config->send_directory = send_directory;
config->receive_root_directory = receive_directory; config->receive_root_directory = receive_directory;
+1 -1
View File
@@ -42,7 +42,7 @@ typedef struct Config {
char* tls_ca; char* tls_ca;
} Config; } Config;
#define PROTOCOL_VERSION "1.3.0" #define PROTOCOL_VERSION "2.0.0"
#define DEFAULT_CHUNK_SIZE (10 * 1024 * 1024) #define DEFAULT_CHUNK_SIZE (10 * 1024 * 1024)
Config* config_create(char* version, char* send_directory, char* receive_directory, Config* config_create(char* version, char* send_directory, char* receive_directory,
+2 -4
View File
@@ -1,11 +1,9 @@
#include "data.h" #include "data.h"
#include "log.h" #include "log.h"
#include <stdlib.h> #include "stdlib.h"
Data* data_create_empty(size_t data_size) { Data* data_create_empty(size_t data_size) {
/* malloc(0) is UB; allocate at least 1 byte but preserve requested size */ void* data = malloc(data_size);
size_t alloc_size = data_size > 0 ? data_size : 1;
void* data = malloc(alloc_size);
if (data == NULL) { if (data == NULL) {
log_message(LOG_LEVEL_ERROR, "Could not allocate memory for empty data"); log_message(LOG_LEVEL_ERROR, "Could not allocate memory for empty data");
return NULL; return NULL;
+1 -1
View File
@@ -1,7 +1,7 @@
#ifndef DATA_H #ifndef DATA_H
#define DATA_H #define DATA_H
#include "stdlib.h" #include <stdlib.h>
typedef struct { typedef struct {
void* data; void* data;
+2 -1
View File
@@ -1,4 +1,5 @@
#include <dirent.h> #include <dirent.h>
#include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <libgen.h> #include <libgen.h>
#include <stddef.h> #include <stddef.h>
@@ -34,7 +35,7 @@ File* file_create(const char* path) {
return NULL; return NULL;
} }
strcpy(file->path, path); memcpy(file->path, path, path_len + 1);
file->data = data_create_reserve(0); file->data = data_create_reserve(0);
if (file->data == NULL) { if (file->data == NULL) {
free(file->path); free(file->path);
+2 -1
View File
@@ -14,7 +14,8 @@ void log_message(LogLevel log_level, char* format, ...) {
if (log_level < current_log_level) if (log_level < current_log_level)
return; return;
time_t now = time(NULL); time_t now = time(NULL);
const struct tm* t = localtime(&now); struct tm result_buf;
const struct tm* t = localtime_r(&now, &result_buf);
fprintf(stderr, "%04d-%02d-%02d %02d:%02d:%02d [%s]: ", t->tm_year + 1900, t->tm_mon + 1, fprintf(stderr, "%04d-%02d-%02d %02d:%02d:%02d [%s]: ", t->tm_year + 1900, t->tm_mon + 1,
t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, log_level_strings[log_level]); t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, log_level_strings[log_level]);
+108 -42
View File
@@ -4,67 +4,103 @@
#include "protocol.h" #include "protocol.h"
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
/*
* Wire format serialization (protocol version 2.0.0+):
* All metadata fields are serialized as fixed-width integers (int32_t / int64_t)
* to ensure cross-platform binary compatiblity. See metadata.h for the
* exact wire layout.
*
* Compile-time assertions verify that the native platform types fit within
* the chosen fixed-width representations.
*/
typedef char static_assert_mode_t_fits[(sizeof(mode_t) <= sizeof(int32_t)) ? 1 : -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];
void metadata_to_buf(char** buf, const FileMetadata* m) { void metadata_to_buf(char** buf, const FileMetadata* m) {
int present = (m != NULL) ? 1 : 0; int32_t present = (m != NULL) ? 1 : 0;
memcpy(*buf, &present, sizeof(int)); memcpy(*buf, &present, sizeof(present));
*buf += sizeof(int); *buf += sizeof(present);
if (m == NULL) if (m == NULL)
return; return;
memcpy(*buf, &m->mode, sizeof(mode_t)); int32_t mode = (int32_t)m->mode;
*buf += sizeof(mode_t); memcpy(*buf, &mode, sizeof(mode));
memcpy(*buf, &m->uid, sizeof(uid_t)); *buf += sizeof(mode);
*buf += sizeof(uid_t); int32_t uid = (int32_t)m->uid;
memcpy(*buf, &m->gid, sizeof(gid_t)); memcpy(*buf, &uid, sizeof(uid));
*buf += sizeof(gid_t); *buf += sizeof(uid);
memcpy(*buf, &m->mtime_sec, sizeof(time_t)); int32_t gid = (int32_t)m->gid;
*buf += sizeof(time_t); memcpy(*buf, &gid, sizeof(gid));
memcpy(*buf, &m->mtime_nsec, sizeof(long)); *buf += sizeof(gid);
*buf += sizeof(long); int64_t mtime_sec = (int64_t)m->mtime_sec;
memcpy(*buf, &mtime_sec, sizeof(mtime_sec));
*buf += sizeof(mtime_sec);
int64_t mtime_nsec = (int64_t)m->mtime_nsec;
memcpy(*buf, &mtime_nsec, sizeof(mtime_nsec));
*buf += sizeof(mtime_nsec);
} }
FileMetadata* metadata_from_buf(char** buf) { FileMetadata* metadata_from_buf(char** buf) {
int present; int32_t present;
memcpy(&present, *buf, sizeof(int)); memcpy(&present, *buf, sizeof(present));
*buf += sizeof(int); *buf += sizeof(present);
if (!present) if (!present)
return NULL; return NULL;
FileMetadata* m = malloc(sizeof(FileMetadata)); FileMetadata* m = malloc(sizeof(FileMetadata));
memcpy(&m->mode, *buf, sizeof(mode_t)); if (m == NULL)
*buf += sizeof(mode_t); return NULL;
memcpy(&m->uid, *buf, sizeof(uid_t)); int32_t mode;
*buf += sizeof(uid_t); memcpy(&mode, *buf, sizeof(mode));
memcpy(&m->gid, *buf, sizeof(gid_t)); *buf += sizeof(mode);
*buf += sizeof(gid_t); m->mode = (mode_t)mode;
memcpy(&m->mtime_sec, *buf, sizeof(time_t)); int32_t uid;
*buf += sizeof(time_t); memcpy(&uid, *buf, sizeof(uid));
memcpy(&m->mtime_nsec, *buf, sizeof(long)); *buf += sizeof(uid);
*buf += sizeof(long); m->uid = (uid_t)uid;
int32_t gid;
memcpy(&gid, *buf, sizeof(gid));
*buf += sizeof(gid);
m->gid = (gid_t)gid;
int64_t mtime_sec;
memcpy(&mtime_sec, *buf, sizeof(mtime_sec));
*buf += sizeof(mtime_sec);
m->mtime_sec = (time_t)mtime_sec;
int64_t mtime_nsec;
memcpy(&mtime_nsec, *buf, sizeof(mtime_nsec));
*buf += sizeof(mtime_nsec);
m->mtime_nsec = (long)mtime_nsec;
return m; return m;
} }
bool metadata_send(int file_descriptor, FileMetadata* m) { bool metadata_send(int file_descriptor, FileMetadata* m) {
if (m == NULL) { if (m == NULL) {
int zero = 0; int32_t zero = 0;
return send_n_data(file_descriptor, &zero, sizeof(int)); return send_n_data(file_descriptor, &zero, sizeof(zero));
} }
int present = 1; int32_t present = 1;
return send_n_data(file_descriptor, &present, sizeof(int)) && int32_t mode = (int32_t)m->mode;
send_n_data(file_descriptor, &m->mode, sizeof(mode_t)) && int32_t uid = (int32_t)m->uid;
send_n_data(file_descriptor, &m->uid, sizeof(uid_t)) && int32_t gid = (int32_t)m->gid;
send_n_data(file_descriptor, &m->gid, sizeof(gid_t)) && int64_t mtime_sec = (int64_t)m->mtime_sec;
send_n_data(file_descriptor, &m->mtime_sec, sizeof(time_t)) && int64_t mtime_nsec = (int64_t)m->mtime_nsec;
send_n_data(file_descriptor, &m->mtime_nsec, sizeof(long)); return send_n_data(file_descriptor, &present, sizeof(present)) &&
send_n_data(file_descriptor, &mode, sizeof(mode)) &&
send_n_data(file_descriptor, &uid, sizeof(uid)) &&
send_n_data(file_descriptor, &gid, sizeof(gid)) &&
send_n_data(file_descriptor, &mtime_sec, sizeof(mtime_sec)) &&
send_n_data(file_descriptor, &mtime_nsec, sizeof(mtime_nsec));
} }
FileMetadata* metadata_receive(int file_descriptor, int* ok) { FileMetadata* metadata_receive(int file_descriptor, int* ok) {
int present; int32_t present;
if (!receive_n_data(file_descriptor, &present, sizeof(int))) { if (!receive_n_data(file_descriptor, &present, sizeof(present))) {
if (ok) if (ok)
*ok = 0; *ok = 0;
return NULL; return NULL;
@@ -80,16 +116,46 @@ FileMetadata* metadata_receive(int file_descriptor, int* ok) {
*ok = 0; *ok = 0;
return NULL; return NULL;
} }
if (!receive_n_data(file_descriptor, &m->mode, sizeof(mode_t)) || int32_t mode;
!receive_n_data(file_descriptor, &m->uid, sizeof(uid_t)) || if (!receive_n_data(file_descriptor, &mode, sizeof(mode))) {
!receive_n_data(file_descriptor, &m->gid, sizeof(gid_t)) ||
!receive_n_data(file_descriptor, &m->mtime_sec, sizeof(time_t)) ||
!receive_n_data(file_descriptor, &m->mtime_nsec, sizeof(long))) {
free(m); free(m);
if (ok) if (ok)
*ok = 0; *ok = 0;
return NULL; return NULL;
} }
m->mode = (mode_t)mode;
int32_t uid;
if (!receive_n_data(file_descriptor, &uid, sizeof(uid))) {
free(m);
if (ok)
*ok = 0;
return NULL;
}
m->uid = (uid_t)uid;
int32_t gid;
if (!receive_n_data(file_descriptor, &gid, sizeof(gid))) {
free(m);
if (ok)
*ok = 0;
return NULL;
}
m->gid = (gid_t)gid;
int64_t mtime_sec;
if (!receive_n_data(file_descriptor, &mtime_sec, sizeof(mtime_sec))) {
free(m);
if (ok)
*ok = 0;
return NULL;
}
m->mtime_sec = (time_t)mtime_sec;
int64_t mtime_nsec;
if (!receive_n_data(file_descriptor, &mtime_nsec, sizeof(mtime_nsec))) {
free(m);
if (ok)
*ok = 0;
return NULL;
}
m->mtime_nsec = (long)mtime_nsec;
if (ok) if (ok)
*ok = 1; *ok = 1;
return m; return m;
+16 -2
View File
@@ -3,10 +3,24 @@
#include "file.h" #include "file.h"
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h>
#include <sys/stat.h> #include <sys/stat.h>
#define FILE_METADATA_WIRE_SIZE \ /*
(sizeof(mode_t) + sizeof(uid_t) + sizeof(gid_t) + sizeof(time_t) + sizeof(long)) * Wire format (introduced in protocol version 2.0.0):
* int32_t present
* int32_t mode (was mode_t, platform-dependent)
* int32_t uid (was uid_t, platform-dependent)
* int32_t gid (was gid_t, platform-dependent)
* int64_t mtime_sec (was time_t, platform-dependent)
* int64_t mtime_nsec (was long, platform-dependent)
*
* Prior to 2.0.0 the wire format used the raw platform-dependent types,
* which broke compatiblity across different systems. All fields are now
* serialized as fixed-width integers.
*/
#define FILE_METADATA_WIRE_SIZE (sizeof(int32_t) * 3 + sizeof(int64_t) * 2)
void metadata_to_buf(char** buf, const FileMetadata* m); void metadata_to_buf(char** buf, const FileMetadata* m);
FileMetadata* metadata_from_buf(char** buf); FileMetadata* metadata_from_buf(char** buf);
+2 -17
View File
@@ -138,10 +138,6 @@ static const char* status_to_string(Status status) {
} }
bool send_str(int file_descriptor, const char* data) { bool send_str(int file_descriptor, const char* data) {
if (data == NULL) {
log_message(LOG_LEVEL_ERROR, "send_str called with NULL data");
return false;
}
size_t size = strlen(data); size_t size = strlen(data);
if (!send_n_data(file_descriptor, &size, sizeof(size_t))) if (!send_n_data(file_descriptor, &size, sizeof(size_t)))
return false; return false;
@@ -155,11 +151,6 @@ char* receive_str(int file_descriptor) {
size_t size; size_t size;
if (!receive_n_data(file_descriptor, &size, sizeof(size_t))) if (!receive_n_data(file_descriptor, &size, sizeof(size_t)))
return NULL; return NULL;
if (size > MAX_STRING_SIZE) {
log_message(LOG_LEVEL_ERROR, "receive_str: size %zu exceeds maximum %zu", size,
(size_t)MAX_STRING_SIZE);
return NULL;
}
char* data = (char*)malloc(size + 1); char* data = (char*)malloc(size + 1);
if (data == NULL) if (data == NULL)
return NULL; return NULL;
@@ -178,20 +169,14 @@ bool send_data(int file_descriptor, const Data* data) {
return false; return false;
if (!send_n_data(file_descriptor, data->data, data_size)) if (!send_n_data(file_descriptor, data->data, data_size))
return false; return false;
log_message(LOG_LEVEL_DEBUG, "Send %llu data", data_size); log_message(LOG_LEVEL_DEBUG, "Send %lld data", data_size);
return true; return true;
} }
#define MAX_DATA_SIZE (1024ULL * 1024 * 1024)
Data* receive_data(int file_descriptor) { Data* receive_data(int file_descriptor) {
unsigned long long size = 0; unsigned long long size = 0;
if (!receive_n_data(file_descriptor, &size, sizeof(unsigned long long))) if (!receive_n_data(file_descriptor, &size, sizeof(unsigned long long)))
return NULL; return NULL;
if ((size_t)size != size || size > MAX_DATA_SIZE) {
log_message(LOG_LEVEL_ERROR, "receive_data size %llu exceeds limits", size);
return NULL;
}
void* data = malloc((size_t)size); void* data = malloc((size_t)size);
if (data == NULL) if (data == NULL)
return NULL; return NULL;
@@ -199,7 +184,7 @@ Data* receive_data(int file_descriptor) {
free(data); free(data);
return NULL; return NULL;
} }
log_message(LOG_LEVEL_DEBUG, "Received %llu data", size); log_message(LOG_LEVEL_DEBUG, "Received %lld data", size);
return data_create(data, (size_t)size); return data_create(data, (size_t)size);
} }
-3
View File
@@ -5,9 +5,6 @@
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
/* Maximum allowed string size for receive_str (10 MB) */
#define MAX_STRING_SIZE (10 * 1024 * 1024)
typedef struct ssl_st SSL; typedef struct ssl_st SSL;
typedef int Status; typedef int Status;
+1 -8
View File
@@ -124,10 +124,7 @@ Client* client_connect_ssh(const char* destination, int port) {
else else
snprintf(ssh_user, sizeof(ssh_user), "%s", r.host); snprintf(ssh_user, sizeof(ssh_user), "%s", r.host);
size_t ssh_argv_max = 32; char* ssh_argv[16];
char** ssh_argv = calloc(ssh_argv_max, sizeof(char*));
if (ssh_argv == NULL)
_exit(1);
int ac = 0; int ac = 0;
char port_str[16]; char port_str[16];
ssh_argv[ac++] = "ssh"; ssh_argv[ac++] = "ssh";
@@ -138,14 +135,10 @@ Client* client_connect_ssh(const char* destination, int port) {
ssh_argv[ac++] = "-o"; ssh_argv[ac++] = "-o";
ssh_argv[ac++] = "ControlPath=~/.cache/fastsync-%r@%h:%p"; ssh_argv[ac++] = "ControlPath=~/.cache/fastsync-%r@%h:%p";
if (port > 0 && port != 22) { if (port > 0 && port != 22) {
if ((size_t)ac + 2 >= ssh_argv_max)
_exit(1);
ssh_argv[ac++] = "-p"; ssh_argv[ac++] = "-p";
snprintf(port_str, sizeof(port_str), "%d", port); snprintf(port_str, sizeof(port_str), "%d", port);
ssh_argv[ac++] = port_str; ssh_argv[ac++] = port_str;
} }
if ((size_t)ac + 3 >= ssh_argv_max)
_exit(1);
ssh_argv[ac++] = ssh_user; ssh_argv[ac++] = ssh_user;
ssh_argv[ac++] = "fastsync-server"; ssh_argv[ac++] = "fastsync-server";
ssh_argv[ac++] = "--stdio"; ssh_argv[ac++] = "--stdio";
+17 -25
View File
@@ -10,23 +10,19 @@
#include <unistd.h> #include <unistd.h>
bool mkdir_r(const char* path) { bool mkdir_r(const char* path) {
size_t path_len = strlen(path); char* path_duplicate = malloc(strlen(path) + 1);
char* path_duplicate = malloc(path_len + 1);
if (!path_duplicate) if (!path_duplicate)
return false; return false;
memcpy(path_duplicate, path, path_len + 1); strcpy(path_duplicate, path);
/* Buffer for building subpaths: path_len + 1 for leading '/' + 1 for null */ char* path_current = (char*)malloc((strlen(path) + 2) * sizeof(char));
size_t buf_size = path_len + 2;
char* path_current = (char*)malloc(buf_size);
if (!path_current) { if (!path_current) {
free(path_duplicate); free(path_duplicate);
return false; return false;
} }
size_t pos = 0; char* path_current_position = path_current;
if (path[0] == '/') { if (path[0] == '/') {
path_current[0] = '/'; strcpy(path_current, "/");
path_current[1] = '\0'; path_current_position += 1;
pos = 1;
} else { } else {
path_current[0] = '\0'; path_current[0] = '\0';
} }
@@ -35,16 +31,10 @@ bool mkdir_r(const char* path) {
const char* part = strtok_r(path_duplicate, delimiter, &saveptr); const char* part = strtok_r(path_duplicate, delimiter, &saveptr);
bool ok = true; bool ok = true;
while (part != NULL) { while (part != NULL) {
size_t part_len = strlen(part); strcpy(path_current_position, part);
if (pos + part_len + 1 >= buf_size) { path_current_position += strlen(part) * sizeof(char);
ok = false; strcpy(path_current_position, "/");
break; path_current_position += sizeof(char);
}
memcpy(path_current + pos, part, part_len);
pos += part_len;
path_current[pos] = '/';
pos++;
path_current[pos] = '\0';
struct stat st; struct stat st;
if (stat(path_current, &st) != 0) { if (stat(path_current, &st) != 0) {
if (mkdir(path_current, 0755) != 0) { if (mkdir(path_current, 0755) != 0) {
@@ -59,11 +49,12 @@ bool mkdir_r(const char* path) {
free(path_current); free(path_current);
return ok; return ok;
} }
char* str_dup(const char* string) { char* str_dup(const char* string) {
if (string == NULL) if (string == NULL)
return NULL; return NULL;
char* new_string = (char*)malloc(strlen(string) + 1); char* new_string = (char*)malloc(strlen(string) + 1);
strcpy(new_string, string); memcpy(new_string, string, strlen(string) + 1);
return new_string; return new_string;
} }
@@ -108,7 +99,7 @@ static void delete_extras_walk(const char* abs_path, const char* rel_path, Array
if (!dir) if (!dir)
return; return;
bool all_removed = true; bool all_removed = true;
const struct dirent* entry; struct dirent* entry;
while ((entry = readdir(dir)) != NULL) { while ((entry = readdir(dir)) != NULL) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue; continue;
@@ -158,17 +149,18 @@ void delete_extras(const char* dest_root, ArrayList* manifest) {
delete_extras_walk(dest_root, "", manifest); delete_extras_walk(dest_root, "", manifest);
} }
char* path_cat(const char* path1, const char* path2) { char* path_cat(const char* path1, char* path2) {
if (path1 == NULL || *path1 == '\0') if (path1 == NULL || *path1 == '\0')
return str_dup(path2); return str_dup(path2);
if (path2 == NULL || *path2 == '\0') if (path2 == NULL || *path2 == '\0')
return str_dup(path1); return str_dup(path1);
int path1_len = strlen(path1); int path1_len = strlen(path1);
int path2_len = strlen(path2); int path2_len = strlen(path2);
char* path2_pointer = path2;
if (path1[path1_len - 1] == '/') if (path1[path1_len - 1] == '/')
path1_len -= 1; path1_len -= 1;
if (path2[0] == '/') { if (path2[0] == '/') {
path2++; path2_pointer += 1;
path2_len -= 1; path2_len -= 1;
} }
char* new_path = malloc(path1_len + path2_len + 2); char* new_path = malloc(path1_len + path2_len + 2);
@@ -176,7 +168,7 @@ char* path_cat(const char* path1, const char* path2) {
return NULL; return NULL;
memcpy(new_path, path1, path1_len); memcpy(new_path, path1, path1_len);
new_path[path1_len] = '/'; new_path[path1_len] = '/';
memcpy(new_path + path1_len + 1, path2, path2_len); memcpy(new_path + path1_len + 1, path2_pointer, path2_len);
new_path[path1_len + path2_len + 1] = '\0'; new_path[path1_len + path2_len + 1] = '\0';
return new_path; return new_path;
} }
+1 -1
View File
@@ -6,7 +6,7 @@
bool mkdir_r(const char* path); bool mkdir_r(const char* path);
char* str_dup(const char* string); char* str_dup(const char* string);
char* path_cat(const char* path1, const char* path2); char* path_cat(const char* path1, char* path2);
bool glob_match(const char* pattern, const char* str); bool glob_match(const char* pattern, const char* str);
void delete_extras(const char* dest_root, ArrayList* manifest); void delete_extras(const char* dest_root, ArrayList* manifest);
-9
View File
@@ -23,14 +23,6 @@ static void test_data_create_empty() {
data_destroy(d); data_destroy(d);
} }
static void test_data_create_empty_zero() {
Data* d = data_create_empty(0);
EXPECT_NOT_NULL(d);
EXPECT_NOT_NULL(d->data);
EXPECT_EQ_INT((int)d->size, 0);
data_destroy(d);
}
static void test_data_create_reserve() { static void test_data_create_reserve() {
Data* d = data_create_reserve(1024); Data* d = data_create_reserve(1024);
EXPECT_NOT_NULL(d); EXPECT_NOT_NULL(d);
@@ -52,7 +44,6 @@ static void test_data_destroy_normal() {
void test_data() { void test_data() {
test_data_create(); test_data_create();
test_data_create_empty(); test_data_create_empty();
test_data_create_empty_zero();
test_data_create_reserve(); test_data_create_reserve();
test_data_destroy_null(); test_data_destroy_null();
test_data_destroy_normal(); test_data_destroy_normal();
-18
View File
@@ -169,23 +169,6 @@ static void test_receive_str_truncated() {
close(p[0]); close(p[0]);
} }
static void test_receive_str_oversized() {
int p[2];
EXPECT_EQ_INT(pipe(p), 0);
io_set_fds(p[0], p[1]);
io_set_bwlimit(0);
/* Send a size exceeding MAX_STRING_SIZE */
size_t huge = MAX_STRING_SIZE + 1;
EXPECT_TRUE(send_n_data(0, &huge, sizeof(size_t)));
const char* received = receive_str(0);
EXPECT_NULL(received);
close(p[0]);
close(p[1]);
}
void test_protocol() { void test_protocol() {
test_send_receive_n_data(); test_send_receive_n_data();
test_send_receive_n_data_zero(); test_send_receive_n_data_zero();
@@ -196,5 +179,4 @@ void test_protocol() {
test_send_receive_status(); test_send_receive_status();
test_receive_n_data_truncated(); test_receive_n_data_truncated();
test_receive_str_truncated(); test_receive_str_truncated();
test_receive_str_oversized();
} }