@@ -66,8 +66,16 @@ Data* data_decompress(Data* compressed_data) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t buf_size =
|
||||
(!ZSTD_isError(dst_size) && dst_size > 0) ? (size_t)dst_size : INITIAL_DECOMPRESS_BUF_SIZE;
|
||||
size_t buf_size = INITIAL_DECOMPRESS_BUF_SIZE;
|
||||
if (!ZSTD_isError(dst_size) && dst_size > 0) {
|
||||
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);
|
||||
if (!uncompressed_data) {
|
||||
log_message(LOG_LEVEL_ERROR, "Failed to allocate decompression buffer");
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include "stdlib.h"
|
||||
|
||||
Data* data_create_empty(size_t data_size) {
|
||||
if (data_size == 0)
|
||||
data_size = 1;
|
||||
void* data = malloc(data_size);
|
||||
if (data == NULL) {
|
||||
log_message(LOG_LEVEL_ERROR, "Could not allocate memory for empty data");
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
#ifndef DATA_H
|
||||
#define DATA_H
|
||||
|
||||
#include "stdlib.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct {
|
||||
void* data;
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ void set_log_level(LogLevel level) {
|
||||
current_log_level = level;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
|
||||
typedef enum { LOG_LEVEL_DEBUG, LOG_LEVEL_INFO, LOG_LEVEL_WARNING, LOG_LEVEL_ERROR } LogLevel;
|
||||
|
||||
void log_message(LogLevel log_level, char* message, ...);
|
||||
void log_message(LogLevel log_level, const char* message, ...);
|
||||
void set_log_level(LogLevel level);
|
||||
|
||||
#endif
|
||||
|
||||
+55
-30
@@ -4,6 +4,7 @@
|
||||
#include "protocol.h"
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -16,16 +17,21 @@ void metadata_to_buf(char** buf, const FileMetadata* m) {
|
||||
*buf += sizeof(int);
|
||||
if (m == NULL)
|
||||
return;
|
||||
memcpy(*buf, &m->mode, sizeof(mode_t));
|
||||
*buf += sizeof(mode_t);
|
||||
memcpy(*buf, &m->uid, sizeof(uid_t));
|
||||
*buf += sizeof(uid_t);
|
||||
memcpy(*buf, &m->gid, sizeof(gid_t));
|
||||
*buf += sizeof(gid_t);
|
||||
memcpy(*buf, &m->mtime_sec, sizeof(time_t));
|
||||
*buf += sizeof(time_t);
|
||||
memcpy(*buf, &m->mtime_nsec, sizeof(long));
|
||||
*buf += sizeof(long);
|
||||
int32_t tmp32 = (int32_t)m->mode;
|
||||
memcpy(*buf, &tmp32, sizeof(int32_t));
|
||||
*buf += sizeof(int32_t);
|
||||
tmp32 = (int32_t)m->uid;
|
||||
memcpy(*buf, &tmp32, sizeof(int32_t));
|
||||
*buf += sizeof(int32_t);
|
||||
tmp32 = (int32_t)m->gid;
|
||||
memcpy(*buf, &tmp32, sizeof(int32_t));
|
||||
*buf += sizeof(int32_t);
|
||||
int64_t tmp64 = (int64_t)m->mtime_sec;
|
||||
memcpy(*buf, &tmp64, sizeof(int64_t));
|
||||
*buf += sizeof(int64_t);
|
||||
tmp64 = (int64_t)m->mtime_nsec;
|
||||
memcpy(*buf, &tmp64, sizeof(int64_t));
|
||||
*buf += sizeof(int64_t);
|
||||
}
|
||||
|
||||
FileMetadata* metadata_from_buf(char** buf) {
|
||||
@@ -35,16 +41,23 @@ FileMetadata* metadata_from_buf(char** buf) {
|
||||
if (!present)
|
||||
return NULL;
|
||||
FileMetadata* m = malloc(sizeof(FileMetadata));
|
||||
memcpy(&m->mode, *buf, sizeof(mode_t));
|
||||
*buf += sizeof(mode_t);
|
||||
memcpy(&m->uid, *buf, sizeof(uid_t));
|
||||
*buf += sizeof(uid_t);
|
||||
memcpy(&m->gid, *buf, sizeof(gid_t));
|
||||
*buf += sizeof(gid_t);
|
||||
memcpy(&m->mtime_sec, *buf, sizeof(time_t));
|
||||
*buf += sizeof(time_t);
|
||||
memcpy(&m->mtime_nsec, *buf, sizeof(long));
|
||||
*buf += sizeof(long);
|
||||
int32_t tmp32;
|
||||
int64_t tmp64;
|
||||
memcpy(&tmp32, *buf, sizeof(int32_t));
|
||||
*buf += sizeof(int32_t);
|
||||
m->mode = (mode_t)tmp32;
|
||||
memcpy(&tmp32, *buf, sizeof(int32_t));
|
||||
*buf += sizeof(int32_t);
|
||||
m->uid = (uid_t)tmp32;
|
||||
memcpy(&tmp32, *buf, sizeof(int32_t));
|
||||
*buf += sizeof(int32_t);
|
||||
m->gid = (gid_t)tmp32;
|
||||
memcpy(&tmp64, *buf, sizeof(int64_t));
|
||||
*buf += sizeof(int64_t);
|
||||
m->mtime_sec = (time_t)tmp64;
|
||||
memcpy(&tmp64, *buf, sizeof(int64_t));
|
||||
*buf += sizeof(int64_t);
|
||||
m->mtime_nsec = (long)tmp64;
|
||||
return m;
|
||||
}
|
||||
|
||||
@@ -54,12 +67,17 @@ bool metadata_send(int file_descriptor, FileMetadata* m) {
|
||||
return send_n_data(file_descriptor, &zero, sizeof(int));
|
||||
}
|
||||
int present = 1;
|
||||
int32_t mode_i32 = (int32_t)m->mode;
|
||||
int32_t uid_i32 = (int32_t)m->uid;
|
||||
int32_t gid_i32 = (int32_t)m->gid;
|
||||
int64_t mtime_sec_i64 = (int64_t)m->mtime_sec;
|
||||
int64_t mtime_nsec_i64 = (int64_t)m->mtime_nsec;
|
||||
return send_n_data(file_descriptor, &present, sizeof(int)) &&
|
||||
send_n_data(file_descriptor, &m->mode, sizeof(mode_t)) &&
|
||||
send_n_data(file_descriptor, &m->uid, sizeof(uid_t)) &&
|
||||
send_n_data(file_descriptor, &m->gid, sizeof(gid_t)) &&
|
||||
send_n_data(file_descriptor, &m->mtime_sec, sizeof(time_t)) &&
|
||||
send_n_data(file_descriptor, &m->mtime_nsec, sizeof(long));
|
||||
send_n_data(file_descriptor, &mode_i32, sizeof(int32_t)) &&
|
||||
send_n_data(file_descriptor, &uid_i32, sizeof(int32_t)) &&
|
||||
send_n_data(file_descriptor, &gid_i32, sizeof(int32_t)) &&
|
||||
send_n_data(file_descriptor, &mtime_sec_i64, sizeof(int64_t)) &&
|
||||
send_n_data(file_descriptor, &mtime_nsec_i64, sizeof(int64_t));
|
||||
}
|
||||
|
||||
FileMetadata* metadata_receive(int file_descriptor, int* ok) {
|
||||
@@ -80,16 +98,23 @@ FileMetadata* metadata_receive(int file_descriptor, int* ok) {
|
||||
*ok = 0;
|
||||
return NULL;
|
||||
}
|
||||
if (!receive_n_data(file_descriptor, &m->mode, sizeof(mode_t)) ||
|
||||
!receive_n_data(file_descriptor, &m->uid, sizeof(uid_t)) ||
|
||||
!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))) {
|
||||
int32_t mode_i32, uid_i32, gid_i32;
|
||||
int64_t mtime_sec_i64, mtime_nsec_i64;
|
||||
if (!receive_n_data(file_descriptor, &mode_i32, sizeof(int32_t)) ||
|
||||
!receive_n_data(file_descriptor, &uid_i32, sizeof(int32_t)) ||
|
||||
!receive_n_data(file_descriptor, &gid_i32, sizeof(int32_t)) ||
|
||||
!receive_n_data(file_descriptor, &mtime_sec_i64, sizeof(int64_t)) ||
|
||||
!receive_n_data(file_descriptor, &mtime_nsec_i64, sizeof(int64_t))) {
|
||||
free(m);
|
||||
if (ok)
|
||||
*ok = 0;
|
||||
return NULL;
|
||||
}
|
||||
m->mode = (mode_t)mode_i32;
|
||||
m->uid = (uid_t)uid_i32;
|
||||
m->gid = (gid_t)gid_i32;
|
||||
m->mtime_sec = (time_t)mtime_sec_i64;
|
||||
m->mtime_nsec = (long)mtime_nsec_i64;
|
||||
if (ok)
|
||||
*ok = 1;
|
||||
return m;
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
|
||||
#include "file.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define FILE_METADATA_WIRE_SIZE \
|
||||
(sizeof(mode_t) + sizeof(uid_t) + sizeof(gid_t) + sizeof(time_t) + sizeof(long))
|
||||
#define FILE_METADATA_WIRE_SIZE (sizeof(int32_t) * 3 + sizeof(int64_t) * 2)
|
||||
|
||||
void metadata_to_buf(char** buf, const FileMetadata* m);
|
||||
FileMetadata* metadata_from_buf(char** buf);
|
||||
|
||||
+54
-16
@@ -34,11 +34,17 @@ static void bw_throttle(size_t bytes_written) {
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
||||
long long elapsed_ns =
|
||||
(now.tv_sec - bw_last_refill.tv_sec) * 1000000000LL + (now.tv_nsec - bw_last_refill.tv_nsec);
|
||||
/* Use unsigned long long for intermediate computation to avoid overflow.
|
||||
* sec_diff * 1000000000LL could overflow a signed 64-bit if the elapsed
|
||||
* time is very large; clamp to a safe maximum. */
|
||||
unsigned long long sec_diff = (unsigned long long)(now.tv_sec - bw_last_refill.tv_sec);
|
||||
if (sec_diff > 9223372036ULL)
|
||||
sec_diff = 9223372036ULL;
|
||||
unsigned long long elapsed_ns =
|
||||
sec_diff * 1000000000ULL + (unsigned long long)(now.tv_nsec - bw_last_refill.tv_nsec);
|
||||
bw_last_refill = now;
|
||||
|
||||
long long tokens_to_add = (long long)((double)io_bwlimit * elapsed_ns / 1000000000.0);
|
||||
long long tokens_to_add = (long long)((double)io_bwlimit * (double)elapsed_ns / 1000000000.0);
|
||||
bw_tokens += tokens_to_add;
|
||||
if (bw_tokens > (long long)io_bwlimit)
|
||||
bw_tokens = (long long)io_bwlimit;
|
||||
@@ -74,13 +80,23 @@ bool send_n_data(int file_descriptor, const void* data, size_t data_size) {
|
||||
if (io_bwlimit > 0 && chunk > 65536)
|
||||
chunk = 65536;
|
||||
ssize_t bytes_send;
|
||||
if (io_ssl)
|
||||
if (io_ssl) {
|
||||
bytes_send = SSL_write(io_ssl, (const char*)data + total_bytes_send, chunk);
|
||||
else
|
||||
if (bytes_send <= 0) {
|
||||
int err = SSL_get_error(io_ssl, (int)bytes_send);
|
||||
if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
|
||||
// Non-fatal: retry without counting progress
|
||||
continue;
|
||||
}
|
||||
log_message(LOG_LEVEL_ERROR, "Could not send data (SSL error: %d)", err);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
bytes_send = write(fd, (const char*)data + total_bytes_send, chunk);
|
||||
if (bytes_send <= 0) {
|
||||
log_message(LOG_LEVEL_ERROR, "Could not send data");
|
||||
return false;
|
||||
if (bytes_send <= 0) {
|
||||
log_message(LOG_LEVEL_ERROR, "Could not send data");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bw_throttle((size_t)bytes_send);
|
||||
total_bytes_send += bytes_send;
|
||||
@@ -95,18 +111,31 @@ bool receive_n_data(int file_descriptor, void* data, size_t data_size) {
|
||||
size_t total_bytes_received = 0;
|
||||
while (total_bytes_received < data_size) {
|
||||
ssize_t bytes_received;
|
||||
if (io_ssl)
|
||||
if (io_ssl) {
|
||||
bytes_received =
|
||||
SSL_read(io_ssl, (char*)data + total_bytes_received, data_size - total_bytes_received);
|
||||
else
|
||||
if (bytes_received <= 0) {
|
||||
int err = SSL_get_error(io_ssl, (int)bytes_received);
|
||||
if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
|
||||
// Non-fatal: retry without counting progress
|
||||
continue;
|
||||
}
|
||||
if (bytes_received == 0)
|
||||
log_message(LOG_LEVEL_ERROR, "Connection closed while receiving data");
|
||||
else
|
||||
log_message(LOG_LEVEL_ERROR, "Could not receive bytes (SSL error: %d)", err);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
bytes_received =
|
||||
read(fd, (char*)data + total_bytes_received, data_size - total_bytes_received);
|
||||
if (bytes_received <= 0) {
|
||||
if (bytes_received == 0)
|
||||
log_message(LOG_LEVEL_ERROR, "Connection closed while receiving data");
|
||||
else
|
||||
log_message(LOG_LEVEL_ERROR, "Could not receive bytes");
|
||||
return false;
|
||||
if (bytes_received <= 0) {
|
||||
if (bytes_received == 0)
|
||||
log_message(LOG_LEVEL_ERROR, "Connection closed while receiving data");
|
||||
else
|
||||
log_message(LOG_LEVEL_ERROR, "Could not receive bytes");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
total_bytes_received += bytes_received;
|
||||
}
|
||||
@@ -138,6 +167,10 @@ static const char* status_to_string(Status status) {
|
||||
}
|
||||
|
||||
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);
|
||||
if (!send_n_data(file_descriptor, &size, sizeof(size_t)))
|
||||
return false;
|
||||
@@ -151,6 +184,11 @@ char* receive_str(int file_descriptor) {
|
||||
size_t size;
|
||||
if (!receive_n_data(file_descriptor, &size, sizeof(size_t)))
|
||||
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);
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
#include <stdbool.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 int Status;
|
||||
|
||||
@@ -124,7 +124,11 @@ Client* client_connect_ssh(const char* destination, int port) {
|
||||
else
|
||||
snprintf(ssh_user, sizeof(ssh_user), "%s", r.host);
|
||||
|
||||
char* ssh_argv[16];
|
||||
/* Max entries: ssh + 3 options*2 each + -p + port + user + cmd + arg + NULL = 13 */
|
||||
size_t ssh_argv_max = 32;
|
||||
char** ssh_argv = calloc(ssh_argv_max, sizeof(char*));
|
||||
if (ssh_argv == NULL)
|
||||
_exit(1);
|
||||
int ac = 0;
|
||||
char port_str[16];
|
||||
ssh_argv[ac++] = "ssh";
|
||||
@@ -135,15 +139,24 @@ Client* client_connect_ssh(const char* destination, int port) {
|
||||
ssh_argv[ac++] = "-o";
|
||||
ssh_argv[ac++] = "ControlPath=~/.cache/fastsync-%r@%h:%p";
|
||||
if (port > 0 && port != 22) {
|
||||
if ((size_t)ac + 2 >= ssh_argv_max) {
|
||||
free(ssh_argv);
|
||||
_exit(1);
|
||||
}
|
||||
ssh_argv[ac++] = "-p";
|
||||
snprintf(port_str, sizeof(port_str), "%d", port);
|
||||
ssh_argv[ac++] = port_str;
|
||||
}
|
||||
if ((size_t)ac + 3 >= ssh_argv_max) {
|
||||
free(ssh_argv);
|
||||
_exit(1);
|
||||
}
|
||||
ssh_argv[ac++] = ssh_user;
|
||||
ssh_argv[ac++] = "fastsync-server";
|
||||
ssh_argv[ac++] = "--stdio";
|
||||
ssh_argv[ac] = NULL;
|
||||
execvp("ssh", ssh_argv);
|
||||
free(ssh_argv);
|
||||
perror("exec of ssh failed");
|
||||
ssize_t wret = write(exec_pipe[1], "x", 1);
|
||||
(void)wret;
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
#ifndef TRANSPORT_TCP_H
|
||||
#define TRANSPORT_TCP_H
|
||||
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdbool.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
typedef struct Server {
|
||||
struct sockaddr_in address;
|
||||
unsigned int address_length;
|
||||
struct sockaddr_storage address;
|
||||
socklen_t address_length;
|
||||
int file_descriptor;
|
||||
int port;
|
||||
void* ssl_ctx;
|
||||
} Server;
|
||||
|
||||
typedef struct Client {
|
||||
struct sockaddr_in address;
|
||||
unsigned int address_length;
|
||||
struct sockaddr_storage address;
|
||||
socklen_t address_length;
|
||||
int file_descriptor;
|
||||
pid_t ssh_child_pid;
|
||||
void* ssl;
|
||||
|
||||
+20
-10
@@ -10,19 +10,23 @@
|
||||
#include <unistd.h>
|
||||
|
||||
bool mkdir_r(const char* path) {
|
||||
char* path_duplicate = malloc(strlen(path) + 1);
|
||||
size_t path_len = strlen(path);
|
||||
char* path_duplicate = malloc(path_len + 1);
|
||||
if (!path_duplicate)
|
||||
return false;
|
||||
strcpy(path_duplicate, path);
|
||||
char* path_current = (char*)malloc((strlen(path) + 2) * sizeof(char));
|
||||
memcpy(path_duplicate, path, path_len + 1);
|
||||
/* Buffer for building subpaths: path_len + 1 for leading '/' + 1 for null */
|
||||
size_t buf_size = path_len + 2;
|
||||
char* path_current = (char*)malloc(buf_size);
|
||||
if (!path_current) {
|
||||
free(path_duplicate);
|
||||
return false;
|
||||
}
|
||||
char* path_current_position = path_current;
|
||||
size_t pos = 0;
|
||||
if (path[0] == '/') {
|
||||
strcpy(path_current, "/");
|
||||
path_current_position += 1;
|
||||
path_current[0] = '/';
|
||||
path_current[1] = '\0';
|
||||
pos = 1;
|
||||
} else {
|
||||
path_current[0] = '\0';
|
||||
}
|
||||
@@ -31,10 +35,16 @@ bool mkdir_r(const char* path) {
|
||||
const char* part = strtok_r(path_duplicate, delimiter, &saveptr);
|
||||
bool ok = true;
|
||||
while (part != NULL) {
|
||||
strcpy(path_current_position, part);
|
||||
path_current_position += strlen(part) * sizeof(char);
|
||||
strcpy(path_current_position, "/");
|
||||
path_current_position += sizeof(char);
|
||||
size_t part_len = strlen(part);
|
||||
if (pos + part_len + 1 >= buf_size) {
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
memcpy(path_current + pos, part, part_len);
|
||||
pos += part_len;
|
||||
path_current[pos] = '/';
|
||||
pos++;
|
||||
path_current[pos] = '\0';
|
||||
struct stat st;
|
||||
if (stat(path_current, &st) != 0) {
|
||||
if (mkdir(path_current, 0755) != 0) {
|
||||
|
||||
Reference in New Issue
Block a user