Refactor logging, add cache-size, fs-event-log (#163)
Much appreciated! Merged. :)
This commit is contained in:
parent
b9ea6ca4c9
commit
441a0d69ed
|
|
@ -0,0 +1,134 @@
|
|||
# Log Management Guide
|
||||
|
||||
This guide covers log configuration and rotation for `pcloudcc`.
|
||||
|
||||
## Log Files
|
||||
|
||||
`pcloudcc` supports two types of logs:
|
||||
|
||||
1. **Debug Log** - Operational information, errors, and debug messages
|
||||
- Default location: `~/.pcloud/debug.log`
|
||||
- Configure with: `--log-path` and `--log-level`
|
||||
|
||||
2. **Filesystem Events Log** - Clean log of file/folder operations only
|
||||
- Disabled by default
|
||||
- Enable with: `--fs-event-log`
|
||||
|
||||
## Log Configuration
|
||||
|
||||
### Log Level
|
||||
|
||||
Control verbosity with `--log-level`:
|
||||
|
||||
```bash
|
||||
# Errors only
|
||||
pcloudcc -u user@example.com -d --log-level ERROR
|
||||
|
||||
# Normal operation (default)
|
||||
pcloudcc -u user@example.com -d --log-level INFO
|
||||
|
||||
# Detailed debugging
|
||||
pcloudcc -u user@example.com -d --log-level DEBUG
|
||||
|
||||
# Disable logging
|
||||
pcloudcc -u user@example.com -d --log-level NONE
|
||||
```
|
||||
|
||||
Available levels: `NONE`, `ERROR`, `WARNING`, `INFO`, `NOTICE`, `DEBUG`
|
||||
|
||||
### Custom Log Path
|
||||
|
||||
```bash
|
||||
# System-wide log
|
||||
pcloudcc -u user@example.com -d --log-path /var/log/pcloudcc.log
|
||||
|
||||
# Custom user location
|
||||
pcloudcc -u user@example.com -d --log-path ~/logs/pcloud.log
|
||||
```
|
||||
|
||||
### Filesystem Events Log
|
||||
|
||||
Enable a separate log containing only filesystem events:
|
||||
|
||||
```bash
|
||||
pcloudcc -u user@example.com -d --fs-event-log ~/.pcloud/fs-events.log
|
||||
```
|
||||
|
||||
Event format: `<timestamp> <event_type> <path>`
|
||||
|
||||
Example events:
|
||||
```
|
||||
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
|
||||
```
|
||||
|
||||
## Log Rotation
|
||||
|
||||
### System-Wide (with logrotate)
|
||||
|
||||
Install the provided configuration:
|
||||
|
||||
```bash
|
||||
sudo cp pcloudcc.logrotate /etc/logrotate.d/pcloudcc
|
||||
```
|
||||
|
||||
This rotates logs daily, keeps 7 days of history, and compresses old logs.
|
||||
|
||||
### User-Specific Rotation
|
||||
|
||||
Create `~/.logrotate.conf`:
|
||||
|
||||
```
|
||||
/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
|
||||
}
|
||||
```
|
||||
|
||||
Add to crontab:
|
||||
|
||||
```bash
|
||||
crontab -e
|
||||
# Add this line:
|
||||
0 2 * * * /usr/sbin/logrotate -s ~/.logrotate.state ~/.logrotate.conf
|
||||
```
|
||||
|
||||
### Manual Rotation
|
||||
|
||||
```bash
|
||||
# Move current logs
|
||||
mv ~/.pcloud/debug.log ~/.pcloud/debug.log.old
|
||||
mv ~/.pcloud/fs-events.log ~/.pcloud/fs-events.log.old
|
||||
|
||||
# Signal pcloudcc to reopen logs
|
||||
pkill -SIGUSR2 pcloudcc
|
||||
```
|
||||
|
||||
## Cache Management
|
||||
|
||||
Configure cache size (default 5GB):
|
||||
|
||||
```bash
|
||||
# Set to 10GB
|
||||
pcloudcc -u user@example.com -d --cache-size 10
|
||||
|
||||
# Set to 1GB for limited storage
|
||||
pcloudcc -u user@example.com -d --cache-size 1
|
||||
```
|
||||
|
||||
Check cache usage:
|
||||
|
||||
```bash
|
||||
du -sh ~/.pcloud/Cache
|
||||
```
|
||||
|
||||
Cache is stored in `~/.pcloud/Cache/` and managed automatically by `pcloudcc`.
|
||||
17
Makefile
17
Makefile
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -39,3 +39,7 @@ 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. To set up automatic log rotation, copy
|
||||
`pcloudcc.logrotate` to `/etc/logrotate.d/pcloudcc`.
|
||||
|
|
|
|||
165
doc/USAGE.md
165
doc/USAGE.md
|
|
@ -4,7 +4,109 @@
|
|||
|
||||
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.
|
||||
|
||||
### FUSE Mount Options
|
||||
|
||||
Pass custom FUSE mount options with `--fuse-opts`:
|
||||
|
||||
```bash
|
||||
# Allow other users to access the mount
|
||||
pcloudcc -u example@myemail.com -d --fuse-opts allow_other
|
||||
|
||||
# Multiple options (comma-separated)
|
||||
pcloudcc -u example@myemail.com -d --fuse-opts allow_other,allow_root
|
||||
|
||||
# Set custom permissions
|
||||
pcloudcc -u example@myemail.com -d --fuse-opts default_permissions,uid=1000,gid=1000
|
||||
```
|
||||
|
||||
**Common FUSE options:**
|
||||
- `allow_other` - Allow all users to access files (requires `/etc/fuse.conf` setting)
|
||||
- `allow_root` - Allow root to access files
|
||||
- `default_permissions` - Enable kernel permission checking
|
||||
- `uid=N`, `gid=N` - Set file owner/group
|
||||
- `umask=OCTAL` - Set file permission mask
|
||||
|
||||
See `man fuse` for complete list of available options.
|
||||
|
||||
## First Use
|
||||
|
||||
|
|
@ -28,11 +130,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
|
||||
|
||||
|
|
|
|||
79
main.cpp
79
main.cpp
|
|
@ -25,6 +25,7 @@
|
|||
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGE.
|
||||
*/
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
|
|
@ -33,6 +34,7 @@
|
|||
#include "control_tools.h"
|
||||
|
||||
#include "pclsync_lib.h"
|
||||
#include "pclsync/psettings.h"
|
||||
|
||||
namespace po = boost::program_options;
|
||||
namespace ct = control_tools;
|
||||
|
|
@ -71,7 +73,12 @@ 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).")
|
||||
("fuse-opts,O", po::value<std::string>(), "FUSE mount options (e.g., 'allow_other,allow_root').");
|
||||
|
||||
po::command_line_parser parser{argc, argv};
|
||||
po::positional_options_description p;
|
||||
|
|
@ -100,9 +107,16 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
|
||||
|
||||
if ((!vm.count("username"))) {
|
||||
// Environment variable fallbacks
|
||||
if (!vm.count("username")) {
|
||||
const char *env_user = std::getenv("PCLOUD_USER");
|
||||
if (env_user && env_user[0])
|
||||
username = env_user;
|
||||
}
|
||||
|
||||
if (!vm.count("username") && username.empty()) {
|
||||
std::cout << "Username option is required, specify with "
|
||||
<< "-u or --username." << std::endl;
|
||||
<< "-u or --username, or set PCLOUD_USER." << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -118,6 +132,11 @@ int main(int argc, char **argv) {
|
|||
cc::clibrary::pclsync_lib::get_lib().set_username(username);
|
||||
if (passwordsw) {
|
||||
cc::clibrary::pclsync_lib::get_lib().read_password();
|
||||
} else {
|
||||
const char *env_pass = std::getenv("PCLOUD_ACCOUNT_PASSWORD");
|
||||
if (env_pass && env_pass[0]) {
|
||||
cc::clibrary::pclsync_lib::get_lib().set_password(std::string(env_pass));
|
||||
}
|
||||
}
|
||||
cc::clibrary::pclsync_lib::get_lib().set_tfa_code(tfa_code);
|
||||
cc::clibrary::pclsync_lib::get_lib().set_trusted_device(trusted_device);
|
||||
|
|
@ -126,8 +145,13 @@ int main(int argc, char **argv) {
|
|||
if (vm.count("passascrypto")) {
|
||||
cc::clibrary::pclsync_lib::get_lib().set_crypto_pass(password);
|
||||
} else {
|
||||
std::cout << "Enter crypto password." << std::endl;
|
||||
cc::clibrary::pclsync_lib::get_lib().read_cryptopass();
|
||||
const char *env_crypto = std::getenv("PCLOUD_CRYPTO_PASSWORD");
|
||||
if (env_crypto && env_crypto[0]) {
|
||||
cc::clibrary::pclsync_lib::get_lib().set_crypto_pass(std::string(env_crypto));
|
||||
} else {
|
||||
std::cout << "Enter crypto password." << std::endl;
|
||||
cc::clibrary::pclsync_lib::get_lib().read_cryptopass();
|
||||
}
|
||||
}
|
||||
} else
|
||||
cc::clibrary::pclsync_lib::get_lib().setup_crypto_ = false;
|
||||
|
|
@ -137,6 +161,51 @@ 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>();
|
||||
/* Validate cache size: minimum 1GB, maximum 1TB */
|
||||
if (cache_size_gb < 1 || cache_size_gb > 1024) {
|
||||
std::cerr << "error: cache-size must be between 1 and 1024 GB" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
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")) {
|
||||
std::string log_path = vm["log-path"].as<std::string>();
|
||||
/* Validate log path: must not be empty or start with /etc or /sys */
|
||||
if (log_path.empty() || log_path.compare(0, 5, "/etc/") == 0 || log_path.compare(0, 5, "/sys/") == 0) {
|
||||
std::cerr << "error: invalid log-path" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
setenv("PCLOUD_LOG_PATH", log_path.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")) {
|
||||
std::string fs_event_log = vm["fs-event-log"].as<std::string>();
|
||||
/* Validate fs-event-log path: must not be empty or start with /etc or /sys */
|
||||
if (fs_event_log.empty() || fs_event_log.compare(0, 5, "/etc/") == 0 || fs_event_log.compare(0, 5, "/sys/") == 0) {
|
||||
std::cerr << "error: invalid fs-event-log" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
setenv("PCLOUD_FS_EVENT_LOG", fs_event_log.c_str(), 1);
|
||||
}
|
||||
|
||||
if (vm.count("fuse-opts")) {
|
||||
setenv("PCLOUD_FUSE_OPTS", vm["fuse-opts"].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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
213
pclsync/pdbg.c
213
pclsync/pdbg.c
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
138
pclsync/pdiff.c
138
pclsync/pdiff.c
|
|
@ -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;
|
||||
|
|
@ -1517,11 +1629,12 @@ static void process_modifyfile(const binresult *entry) {
|
|||
path = pfolder_file_path(fileid, NULL);
|
||||
ptask_lfile_rm(fileid, path);
|
||||
free(path);
|
||||
free(oldfilepath);
|
||||
free(oldfilepath_rel);
|
||||
needdownload = 1;
|
||||
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 ||
|
||||
|
|
@ -1622,13 +1735,28 @@ static void process_deletefile(const binresult *entry) {
|
|||
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() {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
102
pclsync/pfs.c
102
pclsync/pfs.c
|
|
@ -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() {
|
||||
|
|
@ -3632,6 +3690,35 @@ static int psync_fs_do_start() {
|
|||
}
|
||||
fuse_opt_add_arg(&args, "-ohard_remove");
|
||||
|
||||
// Add user-specified FUSE options from environment variable
|
||||
const char *fuse_opts_env = getenv("PCLOUD_FUSE_OPTS");
|
||||
if (fuse_opts_env && fuse_opts_env[0] != '\0') {
|
||||
char *fuse_opts = strdup(fuse_opts_env);
|
||||
if (fuse_opts) {
|
||||
char *saveptr = NULL;
|
||||
char *token = strtok_r(fuse_opts, ",", &saveptr);
|
||||
while (token) {
|
||||
// Trim leading/trailing whitespace
|
||||
while (*token == ' ' || *token == '\t') token++;
|
||||
char *end = token + strlen(token) - 1;
|
||||
while (end > token && (*end == ' ' || *end == '\t')) *end-- = '\0';
|
||||
|
||||
if (strlen(token) > 0) {
|
||||
if (strlen(token) > 250) {
|
||||
pdbg_logf(D_WARNING, "FUSE option too long, skipping: %s", token);
|
||||
} else {
|
||||
char opt_arg[256];
|
||||
snprintf(opt_arg, sizeof(opt_arg), "-o%s", token);
|
||||
fuse_opt_add_arg(&args, opt_arg);
|
||||
pdbg_logf(D_NOTICE, "Adding FUSE option: %s", token);
|
||||
}
|
||||
}
|
||||
token = strtok_r(NULL, ",", &saveptr);
|
||||
}
|
||||
free(fuse_opts);
|
||||
}
|
||||
}
|
||||
|
||||
memset(&psync_oper, 0, sizeof(psync_oper));
|
||||
|
||||
psync_oper.init = psync_fs_init;
|
||||
|
|
@ -3677,9 +3764,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))
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,6 +801,7 @@ prsa_sign_sha256_hash(psync_rsa_privatekey_t rsa,
|
|||
if (!ret)
|
||||
return (psync_rsa_signature_t)(void *)PERROR_NO_MEMORY;
|
||||
ret->datalen = rsalen;
|
||||
/* Save current padding settings using getter functions */
|
||||
padding = mbedtls_rsa_get_padding_mode(rsa);
|
||||
hash_id = mbedtls_rsa_get_md_alg(rsa);
|
||||
mbedtls_rsa_set_padding(rsa, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -46,6 +46,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"
|
||||
|
||||
|
|
@ -56,6 +59,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) {}
|
||||
|
||||
|
|
@ -96,6 +140,9 @@ void clib::pclsync_lib::set_tfa_code(const std::string &arg) {
|
|||
void clib::pclsync_lib::set_username(const std::string &arg) {
|
||||
username_ = arg;
|
||||
}
|
||||
void clib::pclsync_lib::set_password(const std::string &arg) {
|
||||
password_ = arg;
|
||||
}
|
||||
void clib::pclsync_lib::set_crypto_pass(const std::string &arg) {
|
||||
crypto_pass_ = arg;
|
||||
};
|
||||
|
|
@ -499,7 +546,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;
|
||||
}
|
||||
|
||||
|
|
@ -509,6 +557,16 @@ 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') {
|
||||
try {
|
||||
uint64_t cache_size = std::stoull(cache_size_env);
|
||||
psync_set_uint_setting("fscachesize", cache_size);
|
||||
} catch (const std::exception &e) {
|
||||
pdbg_logf(D_ERROR, "Invalid PCLOUD_CACHE_SIZE: %s", cache_size_env);
|
||||
}
|
||||
}
|
||||
|
||||
psync_start_sync(status_change, event_handler);
|
||||
|
||||
username_old = psync_get_username();
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ public:
|
|||
void set_trusted_device(bool arg);
|
||||
void set_tfa_code(const std::string& arg);
|
||||
void set_username(const std::string &arg);
|
||||
void set_password(const std::string &arg);
|
||||
void set_crypto_pass(const std::string &arg);
|
||||
void set_mount(const std::string &arg);
|
||||
void set_savepass(bool s);
|
||||
|
|
|
|||
Loading…
Reference in New Issue