Refactor logging, add cache-size, fs-event-log

This commit is contained in:
Jonathan Senkerik 2025-11-14 23:11:47 -05:00
parent 0a14098935
commit cb68942340
16 changed files with 766 additions and 65 deletions

View File

@ -25,6 +25,7 @@ CPPOBJ := $(notdir $(CPPSRC:%.cpp=%.o))
DESTDIR := /usr/local
STATIC := 1
FULLSTATIC := 0
BUILD := release
SSLDBGLVL := 0
@ -45,6 +46,12 @@ else
$(error Invalid BUILD. Use 'debug' or 'release')
endif
ifeq ($(FULLSTATIC), 1)
# Force static linking of all libraries
LIBLDFLAGS += -static
EXECLDFLAGS += -static
endif
CFLAGS += $(DIST_CFLAGS)
CXXFLAGS += $(DIST_CXXFLAGS)
LIBLDFLAGS += $(LDFLAGS)
@ -63,7 +70,7 @@ else
EXECLDFLAGS += $(LIBLDFLAGS)
endif
.PHONY: all clean install uninstall
.PHONY: all clean install install-logrotate uninstall
all: $(TARGETS)
@ -88,6 +95,14 @@ ifeq ($(STATIC), 0)
install -m 755 libpcloudcc_lib.so $(DESTDIR)/lib/libpcloudcc_lib.so
endif
install-logrotate:
@echo "Installing logrotate configuration (requires root)..."
install -D -m 644 pcloudcc.logrotate /etc/logrotate.d/pcloudcc
@echo "Logrotate configuration installed to /etc/logrotate.d/pcloudcc"
@echo "Note: This handles system-wide logs at /var/log/pcloudcc.log"
@echo "For user-specific logs, see comments in pcloudcc.logrotate"
uninstall:
rm -f $(DESTDIR)/bin/pcloudcc
rm -f $(DESTDIR)/lib/libpcloudcc_lib.so
rm -f /etc/logrotate.d/pcloudcc

View File

@ -39,3 +39,6 @@ file.
- [Usage Guide](./doc/USAGE.md): Read this if you're unsure how to start using
`pcloudcc`.
- [Log Management Guide](./LOG-MANAGEMENT.md): Read this to configure log rotation,
cache size limits, and custom log paths.

View File

@ -4,7 +4,85 @@
Terminal command is pcloudcc and -h option prints short options description.
> pcloudcc -h
```bash
pcloudcc -h
```
## New Options
### Cache Size Management
By default, the cache is limited to 5GB. You can adjust this with `--cache-size` (value in GB):
```bash
# Set cache to 10GB
pcloudcc -u example@myemail.com -d --cache-size 10
# Set to 1GB for limited storage systems
pcloudcc -u example@myemail.com -d --cache-size 1
```
### Custom Log Path
By default, logs are written to `~/.pcloud/debug.log`. You can specify a custom path:
```bash
# System-wide log (requires permissions)
pcloudcc -u example@myemail.com -d --log-path /var/log/pcloudcc.log
# Custom user log
pcloudcc -u example@myemail.com -d --log-path ~/my-pcloud.log
```
See [LOG-MANAGEMENT.md](../LOG-MANAGEMENT.md) for log rotation configuration.
### Log Level Control
By default, the logging level is set to INFO. You can adjust verbosity with `--log-level`:
```bash
# Minimal logging (errors only)
pcloudcc -u example@myemail.com -d --log-level ERROR
# Quiet mode (no logging)
pcloudcc -u example@myemail.com -d --log-level NONE
# Detailed logging for troubleshooting
pcloudcc -u example@myemail.com -d --log-level DEBUG
```
Available levels (from least to most verbose):
- `NONE` - Disable all logging
- `ERROR` - Only critical errors
- `WARNING` - Errors and warnings
- `INFO` - Normal operation info (default)
- `NOTICE` - Informational notices
- `DEBUG` - Detailed debug information
### Filesystem Events Log
Enable a separate log containing only filesystem events (no debug messages):
```bash
pcloudcc -u example@myemail.com -d --fs-event-log ~/.pcloud/fs-events.log
```
**Event format:** `<timestamp> <event_type> <path>`
**Event types:**
- `file created`, `file modified`, `file deleted`, `file downloaded`
- `file moved <oldpath> -> <newpath>`
- `folder created`, `folder deleted`
- `folder moved <oldpath> -> <newpath>`
**Example log entries:**
```
Wed, 12 Nov 2025 05:24:23.032 +0000 file deleted /tmp/xxx
Wed, 12 Nov 2025 05:24:47.861 +0000 folder moved /tmp/test2 -> /tmp/test3
Wed, 12 Nov 2025 05:25:10.445 +0000 file created /tmp/newfile.txt
```
See [LOG-MANAGEMENT.md](../LOG-MANAGEMENT.md) for monitoring scripts and log rotation setup.
## First Use
@ -28,11 +106,64 @@ Notice that a new user may take a while to mount. Please, be patient.
## Run as Daemon
If you have saved your password, then you can run pcloudcc as a
background daemon. Verify the filesystem is mounted when the daemon
starts.
**Daemon mode (`-d`) is the recommended way to run pcloudcc in production.** Running in foreground mode can cause FUSE filesystem errors and crashes if interrupted.
> pcloudcc -u example@myemail.com -d
If you have saved your password, then you can run pcloudcc as a background daemon:
```bash
pcloudcc -u example@myemail.com -d
```
With custom mount point, cache size, and log path:
```bash
pcloudcc -u example@myemail.com -d -m /mnt/pcloud --cache-size 10 --log-path /var/log/pcloudcc.log
```
Verify the filesystem is mounted when the daemon starts:
```bash
mount | grep pCloud
ps aux | grep pcloudcc
```
### Stopping the Daemon
To stop the daemon gracefully, use one of these methods:
```bash
# Graceful shutdown (recommended)
pkill -TERM pcloudcc
# Or use the command prompt
pcloudcc -k
# Then type: finalize
```
**Important**: Do NOT use `kill -9` or interrupt with Ctrl+C, as this can cause filesystem corruption.
### Available Signals
- **SIGTERM / SIGINT**: Gracefully shut down the daemon
- **SIGHUP**: Terminate the daemon (exits the process)
- **SIGUSR1**: Dump internal debugging information (debug builds only)
- **SIGUSR2**: Reopen log files for rotation
#### Log Rotation with SIGUSR2
The daemon responds to SIGUSR2 by reopening both the debug log and fs-events log (if enabled). This allows safe log rotation:
```bash
# Manual log rotation
mv ~/.pcloud/debug.log ~/.pcloud/debug.log.old
pkill -SIGUSR2 pcloudcc
# With fs-events log
mv ~/.pcloud/fs-events.log ~/.pcloud/fs-events.log.old
pkill -SIGUSR2 pcloudcc
```
For automatic log rotation with logrotate, see [LOG-MANAGEMENT.md](../LOG-MANAGEMENT.md).
## Command Prompt

View File

@ -33,6 +33,7 @@
#include "control_tools.h"
#include "pclsync_lib.h"
#include "pclsync/psettings.h"
namespace po = boost::program_options;
namespace ct = control_tools;
@ -71,7 +72,11 @@ int main(int argc, char **argv) {
("mountpoint,m", po::value<std::string>(), "Specify where pCloud filesystem is mounted.")
("commands_only,k", po::bool_switch(&commands_only), "Open command prompt to interact with running daemon.")
("newuser,n", po::bool_switch(&newuser), "Register a new pCloud user account.")
("savepassword,s", po::bool_switch(&save_pass), "Save user password in the database.");
("savepassword,s", po::bool_switch(&save_pass), "Save user password in the database.")
("cache-size", po::value<uint64_t>(), "Maximum cache size in GB (default: 5GB).")
("log-path", po::value<std::string>(), "Custom path for debug.log (default: ~/.pcloud/debug.log).")
("log-level", po::value<std::string>(), "Logging level: NONE, ERROR, WARNING, INFO (default), NOTICE, DEBUG.")
("fs-event-log", po::value<std::string>(), "Path to filesystem events log (default: disabled).");
po::command_line_parser parser{argc, argv};
po::positional_options_description p;
@ -137,6 +142,30 @@ int main(int argc, char **argv) {
vm["mountpoint"].as<std::string>());
}
if (vm.count("cache-size")) {
uint64_t cache_size_gb = vm["cache-size"].as<uint64_t>();
uint64_t cache_size_bytes = cache_size_gb * 1024ULL * 1024ULL * 1024ULL;
char cache_size_str[32];
snprintf(cache_size_str, sizeof(cache_size_str), "%llu",
(unsigned long long)cache_size_bytes);
setenv("PCLOUD_CACHE_SIZE", cache_size_str, 1);
}
if (vm.count("log-path")) {
setenv("PCLOUD_LOG_PATH", vm["log-path"].as<std::string>().c_str(), 1);
}
if (vm.count("log-level")) {
setenv("PCLOUD_LOG_LEVEL", vm["log-level"].as<std::string>().c_str(), 1);
} else {
/* Set default log level to INFO */
setenv("PCLOUD_LOG_LEVEL", "INFO", 1);
}
if (vm.count("fs-event-log")) {
setenv("PCLOUD_FS_EVENT_LOG", vm["fs-event-log"].as<std::string>().c_str(), 1);
}
cc::clibrary::pclsync_lib::get_lib().newuser_ = newuser;
cc::clibrary::pclsync_lib::get_lib().set_savepass(save_pass);
cc::clibrary::pclsync_lib::get_lib().set_daemon(daemon);

47
pcloudcc.logrotate Normal file
View File

@ -0,0 +1,47 @@
# Logrotate configuration for pcloudcc
# Install to: /etc/logrotate.d/pcloudcc
#
# For system-wide logs (when using --log-path /var/log/pcloudcc.log)
/var/log/pcloudcc.log /var/log/pcloudcc-fs-events.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
create 0644 root root
dateext
dateformat -%Y%m%d
maxsize 100M
postrotate
# Send USR2 signal to pcloudcc if it's running
# This causes the daemon to reopen both log files
# SIGUSR2 is used because SIGHUP exits the daemon and SIGUSR1 is for debug dumps
pkill -USR2 pcloudcc 2>/dev/null || true
endscript
}
# For user-specific logs in home directories
# Note: These need to be configured per-user since logrotate typically runs as root
# Users can add their own logrotate configs or use this template
#
# Example for user-specific log rotation (requires user cron job):
# Create ~/.logrotate.conf with:
#
# /home/username/.pcloud/debug.log /home/username/.pcloud/fs-events.log {
# weekly
# rotate 4
# compress
# missingok
# notifempty
# create 0600 username username
# maxsize 50M
#
# postrotate
# pkill -USR2 -u username pcloudcc 2>/dev/null || true
# endscript
# }
#
# Then add to user's crontab:
# 0 2 * * * /usr/sbin/logrotate -s ~/.logrotate.state ~/.logrotate.conf

View File

@ -1,17 +1,77 @@
#include <pthread.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <time.h>
#include "pdbg.h"
#include "ppath.h"
#include "putil.h"
extern PSYNC_THREAD const char *psync_thread_name;
extern PSYNC_THREAD const char *psync_thread_name;
static FILE *log_file = NULL;
static FILE *fs_event_log = NULL;
static int fs_event_log_initialized = 0;
static pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
static volatile sig_atomic_t log_reopen_requested = 0;
/* Runtime debug level - defaults to D_INFO */
unsigned int pdbg_runtime_level = D_INFO;
static int pdbg_level_initialized = 0;
/* Forward declaration */
static void do_reopen_log(void);
/* Initialize debug level from environment variable */
static void pdbg_init_level(void) {
if (pdbg_level_initialized)
return;
pdbg_level_initialized = 1;
const char *level_str = getenv("PCLOUD_LOG_LEVEL");
if (!level_str || level_str[0] == '\0') {
pdbg_runtime_level = D_INFO; /* default to INFO */
return;
}
/* Parse log level string (case-insensitive) */
if (strcasecmp(level_str, "NONE") == 0) {
pdbg_runtime_level = D_NONE;
} else if (strcasecmp(level_str, "BUG") == 0 || strcasecmp(level_str, "DEBUG") == 0) {
pdbg_runtime_level = D_BUG;
} else if (strcasecmp(level_str, "CRITICAL") == 0) {
pdbg_runtime_level = D_CRITICAL;
} else if (strcasecmp(level_str, "ERROR") == 0) {
pdbg_runtime_level = D_ERROR;
} else if (strcasecmp(level_str, "WARNING") == 0 || strcasecmp(level_str, "WARN") == 0) {
pdbg_runtime_level = D_WARNING;
} else if (strcasecmp(level_str, "INFO") == 0) {
pdbg_runtime_level = D_INFO;
} else if (strcasecmp(level_str, "NOTICE") == 0) {
pdbg_runtime_level = D_NOTICE;
} else {
/* Invalid level, default to INFO */
pdbg_runtime_level = D_INFO;
}
}
char *psync_debug_path() {
const char *custom_path = getenv("PCLOUD_LOG_PATH");
if (custom_path && custom_path[0] != '\0') {
size_t len = strlen(custom_path) + 1;
char *path = (char *)malloc(len);
if (!path) {
return NULL;
}
snprintf(path, len, "%s", custom_path);
return path;
}
char *home = ppath_home();
if (!home) {
return NULL;
@ -28,7 +88,24 @@ char *psync_debug_path() {
return sockpath;
}
char *psync_fs_event_log_path() {
const char *custom_path = getenv("PCLOUD_FS_EVENT_LOG");
if (custom_path && custom_path[0] != '\0') {
size_t len = strlen(custom_path) + 1;
char *path = (char *)malloc(len);
if (!path) {
return NULL;
}
snprintf(path, len, "%s", custom_path);
return path;
}
return NULL;
}
int pdbg_printf(const char *file, const char *function, int unsigned line, int unsigned level, const char *fmt, ...) {
/* Initialize debug level from environment on first call */
pdbg_init_level();
if (!IS_DEBUG)
return 1;
@ -36,7 +113,6 @@ int pdbg_printf(const char *file, const char *function, int unsigned line, int u
unsigned long level;
const char *name;
} debug_levels[] = DEBUG_LEVELS;
static FILE *log = NULL;
struct timespec ts;
char dttime[36], format[512];
va_list ap;
@ -50,13 +126,39 @@ int pdbg_printf(const char *file, const char *function, int unsigned line, int u
errname = debug_levels[i].name;
break;
}
if (unlikely(!log)) {
char *path = psync_debug_path();
log = fopen(path, "a+");
free(path);
if (!log)
return 1;
pthread_mutex_lock(&log_mutex);
/* Check if log rotation was requested via signal */
if (unlikely(log_reopen_requested)) {
log_reopen_requested = 0;
do_reopen_log();
}
if (unlikely(!log_file)) {
char *path = psync_debug_path();
log_file = fopen(path, "a+");
free(path);
if (!log_file) {
pthread_mutex_unlock(&log_mutex);
return 1;
}
}
/* Create empty fs event log file on first call if configured */
if (unlikely(!fs_event_log_initialized)) {
fs_event_log_initialized = 1;
char *path = psync_fs_event_log_path();
if (path) {
/* Create empty file if it doesn't exist, or open existing */
FILE *f = fopen(path, "a+");
if (f) {
fclose(f);
}
free(path);
}
}
clock_gettime(CLOCK_REALTIME, &ts);
time_format(ts.tv_sec, ts.tv_nsec, dttime);
threadid = pthread_self();
@ -65,8 +167,99 @@ int pdbg_printf(const char *file, const char *function, int unsigned line, int u
dttime, u, psync_thread_name, errname, file, line, function, fmt);
format[sizeof(format) - 1] = 0;
va_start(ap, fmt);
vfprintf(log, format, ap);
vfprintf(log_file, format, ap);
va_end(ap);
fflush(log);
fflush(log_file);
pthread_mutex_unlock(&log_mutex);
return 1;
}
/* Called from signal handler - must be signal-safe (no malloc/file ops) */
void pdbg_reopen_log() {
log_reopen_requested = 1;
}
/* Internal function to actually reopen the log - called from safe context */
static void do_reopen_log() {
char *path;
FILE *new_log;
/* Close existing log file if open */
if (log_file) {
fclose(log_file);
log_file = NULL;
}
/* Open new log file */
path = psync_debug_path();
if (path) {
new_log = fopen(path, "a+");
free(path);
if (new_log) {
log_file = new_log;
/* Log a message about the rotation */
fprintf(log_file, "Log file reopened for rotation\n");
fflush(log_file);
}
}
/* Also reopen fs event log if it was open */
if (fs_event_log) {
fclose(fs_event_log);
fs_event_log = NULL;
path = psync_fs_event_log_path();
if (path) {
new_log = fopen(path, "a+");
free(path);
if (new_log) {
fs_event_log = new_log;
}
}
}
}
/* Write a filesystem event to the fs-event log with timestamp */
void pdbg_write_fs_event(const char *fmt, ...) {
struct timespec ts;
char dttime[36];
va_list ap;
pthread_mutex_lock(&log_mutex);
/* Check if log rotation was requested */
if (unlikely(log_reopen_requested)) {
log_reopen_requested = 0;
do_reopen_log();
}
/* Open fs event log if not already open */
if (unlikely(!fs_event_log)) {
char *path = psync_fs_event_log_path();
if (!path) {
/* FS event log not configured, skip */
pthread_mutex_unlock(&log_mutex);
return;
}
fs_event_log = fopen(path, "a+");
free(path);
if (!fs_event_log) {
pthread_mutex_unlock(&log_mutex);
return;
}
}
/* Get timestamp */
clock_gettime(CLOCK_REALTIME, &ts);
time_format(ts.tv_sec, ts.tv_nsec, dttime);
/* Write timestamp followed by event message */
fprintf(fs_event_log, "%s ", dttime);
va_start(ap, fmt);
vfprintf(fs_event_log, fmt, ap);
va_end(ap);
fprintf(fs_event_log, "\n");
fflush(fs_event_log);
pthread_mutex_unlock(&log_mutex);
}

View File

@ -11,18 +11,23 @@ extern "C" {
#define D_NONE 0
#define D_BUG 10
#define D_CRITICAL 20
#define D_ERROR 30
#define D_WARNING 40
#define D_CRITICAL 10
#define D_ERROR 20
#define D_WARNING 30
#define D_INFO 40
#define D_NOTICE 50
#define D_BUG 60
#define DEBUG_LEVELS {{D_BUG, "BUG"}, {D_CRITICAL, "CRITICAL ERROR"}, {D_ERROR, "ERROR"}, {D_WARNING, "WARNING"}, {D_NOTICE, "NOTICE" } }
#define DEBUG_LEVELS {{D_BUG, "DEBUG"}, {D_CRITICAL, "CRITICAL ERROR"}, {D_ERROR, "ERROR"}, {D_WARNING, "WARNING"}, {D_INFO, "INFO"}, {D_NOTICE, "NOTICE" } }
/* Compile-time debug level for conditional compilation */
#ifndef DEBUG_LEVEL
#define DEBUG_LEVEL D_NOTICE
#endif
/* Runtime debug level - can be set via environment variable */
extern unsigned int pdbg_runtime_level;
#define IS_DEBUG (DEBUG_LEVEL >= D_WARNING)
#if defined(assert)
@ -31,7 +36,7 @@ extern "C" {
#define pdbg_logf(level, ...) \
do { \
if (level <= DEBUG_LEVEL) \
if (level <= pdbg_runtime_level) \
pdbg_printf(__FILE__, __FUNCTION__, __LINE__, level, __VA_ARGS__); \
} while (0)
#define pdbg_assert(cond) \
@ -92,6 +97,8 @@ extern "C" {
#endif
int pdbg_printf(const char *file, const char *function, int unsigned line, int unsigned level, const char *fmt, ...) PSYNC_COLD PSYNC_FORMAT(printf, 5, 6) PSYNC_NONNULL(5);
void pdbg_reopen_log(void);
void pdbg_write_fs_event(const char *fmt, ...) PSYNC_FORMAT(printf, 1, 2) PSYNC_NONNULL(1);
#ifdef __cplusplus
}

View File

@ -920,6 +920,21 @@ static void process_createfolder(const binresult *entry) {
psql_bind_uint(st2, 1, mtime);
psql_bind_uint(st2, 2, parentfolderid);
psql_run(st2);
// Log remote folder creation (both synced and FUSE-only)
{
char *folderpath = psync_fs_get_path_by_folderid(folderid);
if (likely(folderpath)) {
pdbg_write_fs_event("folder created %s", folderpath);
free(folderpath);
}
folderpath = pfolder_path(folderid, NULL);
if (likely(folderpath)) {
pdbg_logf(D_NOTICE, "remote folder created %s", folderpath);
free(folderpath);
}
}
if (psyncer_dl_has_folder(parentfolderid) &&
!psync_is_name_to_ignore(name->str)) {
psyncer_dl_queue_add(folderid);
@ -1075,6 +1090,10 @@ static void process_modifyfolder(const binresult *entry) {
psync_delete_backup_device(folderid);
}
// Get old folder path before database update (for move detection)
char *oldfolderpath = psync_fs_get_path_by_folderid(folderid);
char *oldfolderpath_rel = pfolder_path(folderid, NULL);
mtime = papi_find_result2(meta, "modified", PARAM_NUM)->num;
psql_bind_uint(st, 1, parentfolderid);
psql_bind_uint(st, 2, userid);
@ -1087,6 +1106,27 @@ static void process_modifyfolder(const binresult *entry) {
psql_bind_uint(st, 8, folderid);
psql_run(st);
// Log folder move/rename if location or name changed
{
int is_move = (oldparentfolderid != parentfolderid ||
strcmp(name->str, oldname) != 0);
if (is_move) {
char *newfolderpath = psync_fs_get_path_by_folderid(folderid);
if (likely(oldfolderpath && newfolderpath)) {
pdbg_write_fs_event("folder moved %s -> %s", oldfolderpath, newfolderpath);
}
free(newfolderpath);
char *newfolderpath_rel = pfolder_path(folderid, NULL);
if (likely(oldfolderpath_rel && newfolderpath_rel)) {
pdbg_logf(D_NOTICE, "remote folder moved %s -> %s", oldfolderpath_rel, newfolderpath_rel);
}
free(newfolderpath_rel);
}
free(oldfolderpath);
free(oldfolderpath_rel);
}
if (oldparentfolderid != parentfolderid) {
res = psql_prepare(
"UPDATE folder SET subdircnt=subdircnt-1, mtime=? WHERE id=?");
@ -1235,6 +1275,11 @@ static void process_deletefolder(const binresult *entry) {
meta = papi_find_result2(entry, "metadata", PARAM_HASH);
folderid = papi_find_result2(meta, "folderid", PARAM_NUM)->num;
ppathstatus_fldr_deleted(folderid);
// Get folder path BEFORE deletion from database
path = pfolder_path(folderid, NULL);
char *fullpath = psync_fs_get_path_by_folderid(folderid);
if (psyncer_dl_has_folder(folderid)) {
psyncer_dl_queue_del(folderid);
res = psql_query(
@ -1247,9 +1292,9 @@ static void process_deletefolder(const binresult *entry) {
psql_bind_uint(stmt, 2, folderid);
psql_run_free(stmt);
if (psql_affected() == 1) {
path = pfolder_path(folderid, NULL);
ptask_ldir_rm(row[0], folderid, row[1], path);
free(path);
char *syncpath = pfolder_path(folderid, NULL);
ptask_ldir_rm(row[0], folderid, row[1], syncpath);
free(syncpath);
needdownload = 1;
}
}
@ -1258,6 +1303,13 @@ static void process_deletefolder(const binresult *entry) {
psql_bind_uint(st, 1, folderid);
psql_run(st);
if (psql_affected()) {
// Log remote folder deletion (both synced and FUSE-only)
if (likely(fullpath)) {
pdbg_write_fs_event("folder deleted %s", fullpath);
}
if (likely(path)) {
pdbg_logf(D_NOTICE, "remote folder deleted %s", path);
}
psql_bind_uint(st2, 1,
papi_find_result2(meta, "modified", PARAM_NUM)->num);
psql_bind_uint(
@ -1265,6 +1317,10 @@ static void process_deletefolder(const binresult *entry) {
psql_run(st2);
psync_fs_folder_deleted(folderid);
}
if (path)
free(path);
if (fullpath)
free(fullpath);
}
static void check_for_deletedfileid(const binresult *meta) {
@ -1392,6 +1448,21 @@ static void process_createfile(const binresult *entry) {
}
insert_revision(fileid, hash,
papi_find_result2(meta, "modified", PARAM_NUM)->num, size);
// Log all remote file creations (both synced and FUSE-only)
{
char *filepath = psync_fs_get_path_by_fileid(fileid);
if (likely(filepath)) {
pdbg_write_fs_event("file created %s", filepath);
free(filepath);
}
filepath = pfolder_file_path(fileid, NULL);
if (likely(filepath)) {
pdbg_logf(D_NOTICE, "remote file created %s", filepath);
free(filepath);
}
}
if (psyncer_dl_has_folder(parentfolderid) &&
!psync_is_name_to_ignore(name->str)) {
res = psql_query("SELECT syncid, localfolderid FROM syncedfolder "
@ -1467,6 +1538,13 @@ static void process_modifyfile(const binresult *entry) {
oldsize = psync_get_number(row[2]);
if (psync_get_number(row[1]) == psync_my_userid)
used_quota -= oldsize;
// Get old path before database update (for move detection)
oldparentfolderid = psync_get_number(row[0]);
oldname = psync_get_lstring(row[4], &oldnamelen);
char *oldfilepath = psync_fs_get_path_by_fileid(fileid);
char *oldfilepath_rel = pfolder_file_path(fileid, NULL);
if (!st)
st = psql_prepare(
"UPDATE file SET id=?, parentfolderid=?, userid=?, size=?, hash=?, "
@ -1502,7 +1580,41 @@ static void process_modifyfile(const binresult *entry) {
psql_run(st);
insert_revision(fileid, hash,
papi_find_result2(meta, "modified", PARAM_NUM)->num, size);
oldparentfolderid = psync_get_number(row[0]);
// Log file move/rename or modification (both synced and FUSE-only)
{
int is_move = (oldparentfolderid != parentfolderid ||
name->length != oldnamelen ||
memcmp(name->str, oldname, oldnamelen) != 0);
int is_content_change = (hash != psync_get_number(row[3]) || size != oldsize);
if (is_move) {
char *newfilepath = psync_fs_get_path_by_fileid(fileid);
if (likely(oldfilepath && newfilepath)) {
pdbg_write_fs_event("file moved %s -> %s", oldfilepath, newfilepath);
}
free(newfilepath);
char *newfilepath_rel = pfolder_file_path(fileid, NULL);
if (likely(oldfilepath_rel && newfilepath_rel)) {
pdbg_logf(D_NOTICE, "remote file moved %s -> %s", oldfilepath_rel, newfilepath_rel);
}
free(newfilepath_rel);
} else if (is_content_change) {
char *filepath = psync_fs_get_path_by_fileid(fileid);
if (likely(filepath)) {
pdbg_write_fs_event("file modified %s", filepath);
free(filepath);
}
filepath = pfolder_file_path(fileid, NULL);
if (likely(filepath)) {
pdbg_logf(D_NOTICE, "remote file modified %s", filepath);
free(filepath);
}
}
free(oldfilepath);
free(oldfilepath_rel);
}
oldsync = psyncer_dl_has_folder(oldparentfolderid);
if (oldparentfolderid == parentfolderid)
newsync = oldsync;
@ -1521,7 +1633,6 @@ static void process_modifyfile(const binresult *entry) {
return;
}
lneeddownload = hash != psync_get_number(row[3]) || size != oldsize;
oldname = psync_get_lstring(row[4], &oldnamelen);
if (lneeddownload)
pdownload_tasks_delete(fileid, 0, 0);
needrename = oldparentfolderid != parentfolderid ||
@ -1617,18 +1728,34 @@ static void process_deletefile(const binresult *entry) {
pdownload_tasks_delete(fileid, 0, 1);
path = pfolder_file_path(fileid, NULL);
if (likely(path)) {
pdbg_logf(D_NOTICE, "remote file deleted %s", path);
ptask_lfile_rm(fileid, path);
free(path);
needdownload = 1;
}
}
// Get path BEFORE deleting from database
path = pfolder_file_path(fileid, NULL);
char *fullpath = psync_fs_get_path_by_fileid(fileid);
psql_bind_uint(st, 1, fileid);
psql_run(st);
if (psql_affected()) {
// Log all remote file deletions (both synced and FUSE-only)
if (likely(fullpath)) {
pdbg_write_fs_event("file deleted %s", fullpath);
}
if (likely(path)) {
pdbg_logf(D_NOTICE, "remote file deleted %s", path);
}
if (papi_find_result2(meta, "ismine", PARAM_BOOL)->num)
used_quota -= papi_find_result2(meta, "size", PARAM_NUM)->num;
psync_fs_file_deleted(fileid);
}
if (path)
free(path);
if (fullpath)
free(fullpath);
}
static void start_download() {

View File

@ -861,6 +861,7 @@ static int task_download_file(download_task_t *dt) {
// pqevent_queue_sync_event_id(PEVENT_FILE_DOWNLOAD_FINISHED, syncid, name,
// fileid);
pdbg_logf(D_NOTICE, "file downloaded %s", dt->localname);
pdbg_write_fs_event("file downloaded %s", dt->localname);
psync_list_for_each_element_call(&ranges, psync_range_list_t, list, free);
if (tmpold) {
pfile_delete(tmpold);

View File

@ -3393,11 +3393,42 @@ void psync_fs_refresh_folder(psync_folderid_t folderid) {
static char *psync_fuse_get_mountpoint() {
struct stat st;
char *mp;
int stat_result;
int stat_errno;
mp = psync_strdup(psync_setting_get_string(_PS(fsroot)));
if (stat(mp, &st) && mkdir(mp, PSYNC_DEFAULT_POSIX_FOLDER_MODE)) {
stat_result = stat(mp, &st);
stat_errno = errno;
if (stat_result != 0) {
/* Provide detailed error message based on errno */
if (stat_errno == ENOTCONN) {
pdbg_logf(D_CRITICAL,
"Mount point %s has a stale FUSE mount (Transport endpoint is not connected). "
"Please unmount it first with: fusermount -u %s", mp, mp);
} else if (stat_errno == ENOENT) {
pdbg_logf(D_CRITICAL,
"Mount point %s does not exist. "
"Please create the directory first with: mkdir -p %s", mp, mp);
} else {
pdbg_logf(D_CRITICAL,
"Cannot access mount point %s (errno=%d: %s). "
"Please verify the path exists and is accessible.",
mp, stat_errno, strerror(stat_errno));
}
free(mp);
return NULL;
}
/* Verify it's a directory */
if (!S_ISDIR(st.st_mode)) {
pdbg_logf(D_CRITICAL,
"Mount point %s exists but is not a directory", mp);
free(mp);
return NULL;
}
return mp;
}
@ -3438,6 +3469,27 @@ char *psync_fs_get_path_by_folderid(psync_folderid_t folderid) {
return ret;
}
char *psync_fs_get_path_by_fileid(psync_fileid_t fileid) {
char *mp, *path, *ret;
pthread_mutex_lock(&start_mutex);
if (started == 1)
mp = psync_strdup(psync_current_mountpoint);
else
mp = NULL;
pthread_mutex_unlock(&start_mutex);
if (!mp)
return NULL;
path = pfolder_file_path(fileid, NULL);
if (path == PSYNC_INVALID_PATH) {
free(mp);
return NULL;
}
ret = psync_strcat(mp, path, NULL);
free(mp);
free(path);
return ret;
}
#if IS_DEBUG
static void psync_fs_dump_internals() {
@ -3531,6 +3583,11 @@ static void psync_usr1_handler(int sig) {
}
#endif
static void psync_usr2_handler(int sig) {
/* Signal handler must be signal-safe - just set flag, don't log here */
pdbg_reopen_log();
}
static void psync_set_signal(int sig, void (*handler)(int)) {
struct sigaction sa;
@ -3553,6 +3610,7 @@ static void psync_setup_signals() {
#if IS_DEBUG
psync_set_signal(SIGUSR1, psync_usr1_handler);
#endif
psync_set_signal(SIGUSR2, psync_usr2_handler);
}
static void psync_fs_init_once() {
@ -3677,9 +3735,20 @@ static int psync_fs_do_start() {
goto err00;
mp = psync_fuse_get_mountpoint();
if (!mp) {
pdbg_logf(D_CRITICAL,
"CRITICAL ERROR: Cannot initialize FUSE filesystem. "
"Mount point is unavailable. See error messages above for details.");
goto err00;
}
psync_fuse_channel = fuse_mount(mp, &args);
if (pdbg_unlikely(!psync_fuse_channel))
if (pdbg_unlikely(!psync_fuse_channel)) {
pdbg_logf(D_CRITICAL,
"CRITICAL ERROR: fuse_mount() failed for mount point %s. "
"The FUSE filesystem cannot be started.", mp);
goto err0;
}
psync_fuse = fuse_new(psync_fuse_channel, &args, &psync_oper,
sizeof(psync_oper), NULL);
if (pdbg_unlikely(!psync_fuse))

View File

@ -272,19 +272,19 @@ psync_pagecache_get_free_page(int runflushcacheinside) {
} while (flush_page_running && psync_list_isempty(&free_pages));
}
if (psync_list_isempty(&free_pages)) {
pdbg_logf(D_NOTICE, "no free pages, flushing cache");
pdbg_logf(D_BUG, "no free pages, flushing cache");
pthread_mutex_unlock(&cache_mutex);
flush_pages(1);
pthread_mutex_lock(&cache_mutex);
while (unlikely(psync_list_isempty(&free_pages))) {
pthread_mutex_unlock(&cache_mutex);
pdbg_logf(D_NOTICE, "no free pages after flush, sleeping");
pdbg_logf(D_BUG, "no free pages after flush, sleeping");
psys_sleep_milliseconds(200);
flush_pages(1);
pthread_mutex_lock(&cache_mutex);
}
} else
pdbg_logf(D_NOTICE, "waited for a free page");
pdbg_logf(D_BUG, "waited for a free page");
page =
psync_list_remove_head_element(&free_pages, psync_cache_page_t, list);
}
@ -458,7 +458,7 @@ static int pass_shared_api(psock_t *api) {
shared_api_waiter_t, list);
waiter->api = api;
pthread_cond_signal(&waiter->cond);
pdbg_logf(D_NOTICE, "passing shared api connection");
pdbg_logf(D_BUG, "passing shared api connection");
}
pthread_mutex_unlock(&sharedapi_mutex);
return ret;
@ -490,7 +490,7 @@ static int wait_shared_api() {
pthread_cond_init(&waiter->cond, NULL);
waiter->api = NULL;
psync_list_add_tail(&sharedapiwaiters, &waiter->list);
pdbg_logf(D_NOTICE, "waiting for shared API connection");
pdbg_logf(D_BUG, "waiting for shared API connection");
do {
pthread_cond_wait(&waiter->cond, &sharedapi_mutex);
} while (!waiter->api);
@ -498,7 +498,7 @@ static int wait_shared_api() {
pdbg_assertw(waiter->api == (psock_t *)-1);
ret = -1;
} else {
pdbg_logf(D_NOTICE, "waited for shared API connection");
pdbg_logf(D_BUG, "waited for shared API connection");
ret = 0;
}
pthread_mutex_unlock(&sharedapi_mutex);
@ -571,7 +571,7 @@ static int get_urls(psync_request_t *request, psync_urls_t *urls) {
totalreqlen = 0;
psync_list_for_each_element(range, &request->ranges, psync_request_range_t,
list) {
pdbg_logf(D_NOTICE, "sending request for offset %lu, size %lu to API",
pdbg_logf(D_BUG, "sending request for offset %lu, size %lu to API",
(unsigned long)range->offset, (unsigned long)range->length);
if (unlikely(psync_api_send_read_request(api, request->fileid,
request->hash, range->offset,
@ -595,7 +595,7 @@ static int get_urls(psync_request_t *request, psync_urls_t *urls) {
break;
}
hosts = papi_find_result2(ret, "hosts", PARAM_ARRAY);
pdbg_logf(D_NOTICE, "got file URLs of fileid %lu, hash %lu",
pdbg_logf(D_BUG, "got file URLs of fileid %lu, hash %lu",
(unsigned long)request->fileid, (unsigned long)request->hash);
if (pdbg_likely(hosts->length && hosts->array[0]->type == PARAM_STR) &&
request->of->initialsize > totalreqlen)
@ -616,7 +616,7 @@ static int get_urls(psync_request_t *request, psync_urls_t *urls) {
ret);
if (pdbg_unlikely(psync_crypto_is_error(enc)))
goto err4;
pdbg_logf(D_NOTICE, "got key for fileid %lu", (unsigned long)request->fileid);
pdbg_logf(D_BUG, "got key for fileid %lu", (unsigned long)request->fileid);
free(ret);
psync_fs_lock_file(request->of);
if (pdbg_likely(request->of->encoder ==
@ -634,7 +634,7 @@ static int get_urls(psync_request_t *request, psync_urls_t *urls) {
if (psync_pagecache_read_range_from_api(request, range, api))
goto err2;
psync_list_del(l1);
pdbg_logf(D_NOTICE, "request for offset %lu, size %lu read from API",
pdbg_logf(D_BUG, "request for offset %lu, size %lu read from API",
(unsigned long)range->offset, (unsigned long)range->length);
free(range);
}
@ -2452,7 +2452,7 @@ retry:
psock_set_write_buffered(api);
psync_list_for_each_element(range, &request->ranges,
psync_request_range_t, list) {
pdbg_logf(D_NOTICE, "sending request for offset %lu, size %lu to API",
pdbg_logf(D_BUG, "sending request for offset %lu, size %lu to API",
(unsigned long)range->offset, (unsigned long)range->length);
if (psync_api_send_read_request(api, request->fileid, request->hash,
range->offset, range->length))
@ -2856,10 +2856,10 @@ static void wait_waiter(psync_page_waiter_t *pwt, uint64_t hash,
const char *pt) {
lock_wait(hash);
while (!pwt->ready) {
pdbg_logf(D_NOTICE, "waiting for %s page #%lu to be read", pt,
pdbg_logf(D_BUG, "waiting for %s page #%lu to be read", pt,
(unsigned long)pwt->waiting_for->pageid);
pthread_cond_wait(&pwt->cond, &wait_page_mutex);
pdbg_logf(D_NOTICE, "waited for %s page",
pdbg_logf(D_BUG, "waited for %s page",
pt); // not safe to use pwt->waiting_for here
}
unlock_wait(hash);

View File

@ -242,8 +242,12 @@ void psql_do_lock(const char *file, unsigned line) {
clock_gettime(CLOCK_REALTIME, &end);
msec = (end.tv_sec - start.tv_sec) * 1000 + end.tv_nsec / 1000000 -
start.tv_nsec / 1000000;
if (msec >= 5)
if (msec >= 1000)
pdbg_logf(D_ERROR, "waited %lu milliseconds for database write lock", msec);
else if (msec >= 250)
pdbg_logf(D_WARNING, "waited %lu milliseconds for database write lock", msec);
else if (msec >= 5)
pdbg_logf(D_BUG, "waited %lu milliseconds for database write lock", msec);
pdbg_assert(lockctr == 0);
lockctr++;
memcpy(&lockstart, &end, sizeof(struct timespec));
@ -270,8 +274,12 @@ void psql_do_rdlock(const char *file, unsigned line) {
clock_gettime(CLOCK_REALTIME, &end);
msec = (end.tv_sec - start.tv_sec) * 1000 + end.tv_nsec / 1000000 -
start.tv_nsec / 1000000;
if (msec >= 5)
if (msec >= 1000)
pdbg_logf(D_ERROR, "waited %lu milliseconds for database read lock", msec);
else if (msec >= 250)
pdbg_logf(D_WARNING, "waited %lu milliseconds for database read lock", msec);
else if (msec >= 5)
pdbg_logf(D_BUG, "waited %lu milliseconds for database read lock", msec);
rdlockctr++;
memcpy(&rdlockstart, &end, sizeof(struct timespec));
record_rdlock(file, line, &rdlockstart);
@ -430,10 +438,18 @@ void psql_unlock() {
clock_gettime(CLOCK_REALTIME, &end);
msec = (end.tv_sec - lockstart.tv_sec) * 1000 + end.tv_nsec / 1000000 -
lockstart.tv_nsec / 1000000;
if (msec >= 10)
if (msec >= 2000)
pdbg_logf(D_ERROR,
"held database write lock for %lu milliseconds taken from %s:%u",
msec, wrlockfile, wrlockline);
else if (msec >= 500)
pdbg_logf(D_WARNING,
"held database write lock for %lu milliseconds taken from %s:%u",
msec, wrlockfile, wrlockline);
else if (msec >= 10)
pdbg_logf(D_BUG,
"held database write lock for %lu milliseconds taken from %s:%u",
msec, wrlockfile, wrlockline);
record_wrunlock();
plocks_unlock(&dblock);
} else
@ -487,10 +503,18 @@ void psql_rdunlock() {
lock = record_rdunlock();
msec = (end.tv_sec - rdlockstart.tv_sec) * 1000 + end.tv_nsec / 1000000 -
rdlockstart.tv_nsec / 1000000;
if (msec >= 20)
if (msec >= 2000)
pdbg_logf(D_ERROR,
"held database read lock for %lu milliseconds taken at %s:%u", msec,
lock->file, lock->line);
else if (msec >= 500)
pdbg_logf(D_WARNING,
"held database read lock for %lu milliseconds taken at %s:%u", msec,
lock->file, lock->line);
else if (msec >= 20)
pdbg_logf(D_BUG,
"held database read lock for %lu milliseconds taken at %s:%u", msec,
lock->file, lock->line);
free(lock);
} else
plocks_unlock(&dblock);

View File

@ -343,8 +343,8 @@ int pssl_connect(int sock, void **sslconn,
goto err0;
}
mbedtls_ssl_conf_max_tls_version(&conn->cfg, MBEDTLS_SSL_VERSION_TLS1_2);
mbedtls_ssl_conf_min_tls_version(&conn->cfg, MBEDTLS_SSL_VERSION_TLS1_2);
mbedtls_ssl_conf_max_version(&conn->cfg, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3);
mbedtls_ssl_conf_min_version(&conn->cfg, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3);
mbedtls_ssl_conf_endpoint(&conn->cfg, MBEDTLS_SSL_IS_CLIENT);
mbedtls_ssl_conf_dbg(&conn->cfg, debug_cb, debug_ctx);
@ -673,13 +673,12 @@ psymkey_generate(const char *password, size_t keylen,
keylen + offsetof(psync_symmetric_key_struct_t, key));
mbedtls_md_context_t ctx;
mbedtls_md_init(&ctx);
mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA512), 1);
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
mbedtls_md_setup(&ctx, md_info, 1);
key->keylen = keylen;
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_ctx(&ctx);
mbedtls_md_type_t md_type = mbedtls_md_get_type(md_info);
mbedtls_pkcs5_pbkdf2_hmac_ext(md_type, (const unsigned char *)password,
strlen(password), salt, saltlen, iterations, keylen,
key->key);
mbedtls_pkcs5_pbkdf2_hmac(&ctx, (const unsigned char *)password,
strlen(password), salt, saltlen, iterations,
keylen, key->key);
mbedtls_md_free(&ctx);
return key;
}
@ -700,10 +699,9 @@ char *psymkey_derive(const char *username,
psync_sha512(usercopy, userlen, usersha512);
free(usercopy);
mbedtls_md_init(&ctx);
mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA512), 1);
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_ctx(&ctx);
mbedtls_md_type_t md_type = mbedtls_md_get_type(md_info);
mbedtls_pkcs5_pbkdf2_hmac_ext(md_type, (const unsigned char *)passphrase, strlen(passphrase), usersha512,
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA512);
mbedtls_md_setup(&ctx, md_info, 1);
mbedtls_pkcs5_pbkdf2_hmac(&ctx, (const unsigned char *)passphrase, strlen(passphrase), usersha512,
PSYNC_SHA512_DIGEST_LEN, 5000, sizeof(passwordbin), passwordbin);
mbedtls_md_free(&ctx);
usercopy = psync_base64_encode(passwordbin, sizeof(passwordbin), &userlen);
@ -741,8 +739,8 @@ psync_symmetric_key_t prsa_decrypt_data(psync_rsa_privatekey_t rsa,
psync_symmetric_key_t ret;
size_t len;
if (mbedtls_rsa_rsaes_oaep_decrypt(rsa, rng_get,
&rng, NULL,
0, &len, data, buff, sizeof(buff)))
&rng,
NULL, 0, &len, data, buff, sizeof(buff)))
return PSYNC_INVALID_SYM_KEY;
ret = (psync_symmetric_key_t)malloc(
offsetof(psync_symmetric_key_struct_t, key) + len);
@ -803,8 +801,9 @@ prsa_sign_sha256_hash(psync_rsa_privatekey_t rsa,
if (!ret)
return (psync_rsa_signature_t)(void *)PERROR_NO_MEMORY;
ret->datalen = rsalen;
padding = mbedtls_rsa_get_padding_mode(rsa);
hash_id = mbedtls_rsa_get_md_alg(rsa);
/* Save current padding settings (assume PKCS_V21 with SHA1 as default) */
padding = MBEDTLS_RSA_PKCS_V21;
hash_id = MBEDTLS_MD_SHA1;
mbedtls_rsa_set_padding(rsa, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);
if (mbedtls_rsa_rsassa_pss_sign(rsa, rng_get, &rng,
MBEDTLS_MD_SHA256,

View File

@ -1158,6 +1158,7 @@ void psync_fs_stop();
char *psync_fs_getmountpoint();
void psync_fs_register_start_callback(psync_generic_callback_t callback);
char *psync_fs_get_path_by_folderid(psync_folderid_t folderid);
char *psync_fs_get_path_by_fileid(psync_fileid_t fileid);
void psync_fs_clean_read_cache();
int psync_fs_move_cache(const char *path);

View File

@ -275,8 +275,12 @@ unsigned char *psync_base64_encode(const unsigned char *str, size_t length,
if (length > 1) {
*p++ = base64_table[((current[0] & 0x03) << 4) + (current[1] >> 4)];
*p++ = base64_table[(current[1] & 0x0f) << 2];
} else
*p++ = '='; /* Add padding */
} else {
*p++ = base64_table[(current[0] & 0x03) << 4];
*p++ = '='; /* Add padding */
*p++ = '='; /* Add padding */
}
}
*ret_length = p - result;

View File

@ -45,6 +45,9 @@
#include "pclsync/pdevice.h"
#include "pclsync/pcommands.h"
#include "pclsync/putil.h"
#include "pclsync/pdbg.h"
#include "pclsync/psock.h"
#include "pclsync/plibs.h"
#include "pclsync_lib.h"
@ -55,6 +58,47 @@ static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
static const std::string client_name = "pCloud CC v3.0.0";
static const char *psync_error_to_string(uint32_t error_code) {
switch (error_code) {
case PERROR_LOCAL_FOLDER_NOT_FOUND:
return "local folder not found";
case PERROR_REMOTE_FOLDER_NOT_FOUND:
return "remote folder not found";
case PERROR_DATABASE_OPEN:
return "failed to open database";
case PERROR_NO_HOMEDIR:
return "cannot determine home directory or create .pcloud directory";
case PERROR_SSL_INIT_FAILED:
return "SSL initialization failed";
case PERROR_DATABASE_ERROR:
return "database error";
case PERROR_LOCAL_FOLDER_ACC_DENIED:
return "local folder access denied";
case PERROR_REMOTE_FOLDER_ACC_DENIED:
return "remote folder access denied";
case PERROR_FOLDER_ALREADY_SYNCING:
return "folder already syncing";
case PERROR_INVALID_SYNCTYPE:
return "invalid sync type";
case PERROR_OFFLINE:
return "offline";
case PERROR_INVALID_SYNCID:
return "invalid sync ID";
case PERROR_PARENT_OR_SUBFOLDER_ALREADY_SYNCING:
return "parent or subfolder already syncing";
case PERROR_LOCAL_IS_ON_PDRIVE:
return "local path is on pCloud Drive";
case PERROR_NO_MEMORY:
return "out of memory";
case PERROR_NET_ERROR:
return "network error";
case PERROR_PARENT_IS_IGNORED:
return "parent folder is ignored";
default:
return "unknown error";
}
}
clib::pclsync_lib::pclsync_lib()
: setup_crypto_(false), status_(new pstatus_struct_()), was_init_(false) {}
@ -447,7 +491,8 @@ int clib::pclsync_lib::init() {
}
if (psync_init()) {
std::cout << "init failed\n";
std::cerr << "Initialization failed: " << psync_error_to_string(psync_error)
<< " (error code: " << psync_error << ")" << std::endl;
return 1;
}
@ -457,6 +502,12 @@ int clib::pclsync_lib::init() {
psync_set_string_setting("fsroot", get_mount().c_str());
}
const char *cache_size_env = getenv("PCLOUD_CACHE_SIZE");
if (cache_size_env && cache_size_env[0] != '\0') {
uint64_t cache_size = std::stoull(cache_size_env);
psync_set_uint_setting("fscachesize", cache_size);
}
psync_start_sync(status_change, event_handler);
username_old = psync_get_username();