Remove unimplemented CLI options
CI / lint (pull_request) Failing after 3s
CI / build-and-test (pull_request) Has been skipped
CI / sanitizers (address) (pull_request) Has been skipped
CI / sanitizers (undefined) (pull_request) Has been skipped
CI / fuzz-build (pull_request) Has been skipped
CI / coverage (pull_request) Has been skipped
CI / valgrind (pull_request) Has been skipped

This commit is contained in:
2026-08-11 20:59:06 +02:00
parent 09fca8d931
commit d146e1bb7c
11 changed files with 138 additions and 385 deletions
+4 -12
View File
@@ -40,12 +40,10 @@ A high-performance file synchronization system with SSH and TCP transport, TLS e
- Optional progress display with throughput - Optional progress display with throughput
- Bandwidth limiting via token-bucket algorithm - Bandwidth limiting via token-bucket algorithm
- Configurable I/O and connection timeouts (`--timeout`, `--contimeout`) - Configurable I/O and connection timeouts (`--timeout`, `--contimeout`)
- Quiet mode (`-q`/`--quiet`) suppresses all non-error output
- Backup overwritten files (`--backup`) with optional directory (`--backup-dir`) - Backup overwritten files (`--backup`) with optional directory (`--backup-dir`)
- Transfer statistics summary (`--stats`) - Transfer statistics summary (`--stats`)
- Maximum directory depth control (`--max-depth`) - Maximum directory depth control (`--max-depth`)
- Log file output (`--log-file`) - Log file output (`--log-file`)
- Configurable multithreaded queue size (`--queue-size`)
- Exclude patterns from file (`--exclude-from`) - Exclude patterns from file (`--exclude-from`)
### Server ### Server
@@ -114,8 +112,6 @@ Abort (`STATUS_ABORT`) may be sent at any point. On receipt the server cleans up
| `-n, --dry-run` | Scan and print what would be transferred | | `-n, --dry-run` | Scan and print what would be transferred |
| `-p <port>` | SSH port (default: 22) | | `-p <port>` | SSH port (default: 22) |
| `-v, --verbose` | Enable debug logging | | `-v, --verbose` | Enable debug logging |
| `-q, --quiet` | Suppress all non-error output |
| `--silent` | Alias for `--quiet` |
| `--progress` | Show real-time transfer speed | | `--progress` | Show real-time transfer speed |
| `--delete` | Delete files on receiver not present in source | | `--delete` | Delete files on receiver not present in source |
| `--exclude <pattern>` | Exclude files matching glob pattern (repeatable) | | `--exclude <pattern>` | Exclude files matching glob pattern (repeatable) |
@@ -133,7 +129,6 @@ Abort (`STATUS_ABORT`) may be sent at any point. On receipt the server cleans up
| `--stats` | Print transfer statistics at end (bytes, files, timing) | | `--stats` | Print transfer statistics at end (bytes, files, timing) |
| `--max-depth <n>` | Maximum directory depth to recurse (0 = unlimited, default: 0) | | `--max-depth <n>` | Maximum directory depth to recurse (0 = unlimited, default: 0) |
| `--log-file <path>` | Write log messages to file instead of stderr | | `--log-file <path>` | Write log messages to file instead of stderr |
| `--queue-size <n>` | Queue capacity for multithreaded mode (default: 100) |
| `--source-dir <path>` | Source directory (overrides `FASTSYNC_SOURCE_DIR`) | | `--source-dir <path>` | Source directory (overrides `FASTSYNC_SOURCE_DIR`) |
| `--dest-dir <path>` | Server destination directory (overrides `FASTSYNC_DEST_DIR`) | | `--dest-dir <path>` | Server destination directory (overrides `FASTSYNC_DEST_DIR`) |
| `--save-to-disk` | Write received files to disk | | `--save-to-disk` | Write received files to disk |
@@ -177,7 +172,7 @@ Abort (`STATUS_ABORT`) may be sent at any point. On receipt the server cleans up
1. **Chunk** — collection of files (~10 MB total by default) 1. **Chunk** — collection of files (~10 MB total by default)
2. **File** — path, content (`Data`), optional `FileMetadata` pointer 2. **File** — path, content (`Data`), optional `FileMetadata` pointer
3. **FileMetadata**`mode`, `uid`, `gid`, `mtime_sec`, `mtime_nsec` 3. **FileMetadata**`mode`, `uid`, `gid`, `mtime_sec`, `mtime_nsec`
4. **Config** — runtime parameters (transported over wire, TLS settings excluded). Includes `timeout`, `contimeout`, `quiet`, `backup`, `backup_dir`, `stats`, `max_depth`, `log_file`, `queue_size`. 4. **Config** — runtime parameters (transported over wire, TLS settings excluded). Includes `timeout`, `contimeout`, `backup`, `backup_dir`, `stats`, and `max_depth`.
5. **Queue** — thread-safe bounded queue with condition variables 5. **Queue** — thread-safe bounded queue with condition variables
6. **DirectoryScanner** — recursive BFS traversal with exclude and include pattern support, max-depth enforcement 6. **DirectoryScanner** — recursive BFS traversal with exclude and include pattern support, max-depth enforcement
@@ -294,8 +289,8 @@ Place the `fastsync-server` binary in the remote `$PATH`. The client runs `ssh u
# Bandwidth limit to 1 MB/s # Bandwidth limit to 1 MB/s
./build/client --bwlimit 1024 /src user@host:/dst ./build/client --bwlimit 1024 /src user@host:/dst
# With timeouts, quiet mode, and stats # With timeouts and stats
./build/client --timeout 60 --contimeout 15 --quiet --stats /src user@host:/dst ./build/client --timeout 60 --contimeout 15 --stats /src user@host:/dst
# Backup overwritten files to a directory # Backup overwritten files to a directory
./build/client --backup --backup-dir /backups /src user@host:/dst ./build/client --backup --backup-dir /backups /src user@host:/dst
@@ -303,9 +298,6 @@ Place the `fastsync-server` binary in the remote `$PATH`. The client runs `ssh u
# Exclude patterns from file, limit depth # Exclude patterns from file, limit depth
./build/client --exclude-from ignore.txt --max-depth 3 /src user@host:/dst ./build/client --exclude-from ignore.txt --max-depth 3 /src user@host:/dst
# Custom queue size for multithreading
./build/client -m --queue-size 200 /src user@host:/dst
# Log to file # Log to file
./build/client --log-file /tmp/fastsync.log /src user@host:/dst ./build/client --log-file /tmp/fastsync.log /src user@host:/dst
@@ -332,7 +324,7 @@ The benchmark prints throughput metrics, best configuration, and speedup vs rsyn
1. Chunk size (~10 MB default) balances memory and transfer efficiency 1. Chunk size (~10 MB default) balances memory and transfer efficiency
2. Compression level trades CPU for bandwidth 2. Compression level trades CPU for bandwidth
3. `sendfile()` bypasses userspace — ~2× faster on localhost for large files 3. `sendfile()` bypasses userspace — ~2× faster on localhost for large files
4. Multithreading scales with core count; `--queue-size` controls pipeline buffering 4. Multithreading scales with core count and uses memory-based pipeline sizing
5. Metadata transfer adds negligible overhead (~24 bytes per file when enabled) 5. Metadata transfer adds negligible overhead (~24 bytes per file when enabled)
6. SSH socketpair buffer set to 1 MB for improved pipe throughput 6. SSH socketpair buffer set to 1 MB for improved pipe throughput
7. SSH ControlMaster reuses connections across repeated invocations 7. SSH ControlMaster reuses connections across repeated invocations
+42 -43
View File
@@ -6,10 +6,10 @@ This document maps rsync's full feature set to FastSync's current implementation
| Status | Count | Description | | Status | Count | Description |
|--------|-------|-------------| |--------|-------|-------------|
| ✅ Implemented | 39 | Feature works end-to-end | | ✅ Implemented | 34 | Feature works end-to-end |
| 🔀 Alt Arg | 5 | Functionality exists but under different flag/semantics | | 🔀 Alt Arg | 3 | Functionality exists but under different flag/semantics |
| ⚠️ Partial | 30 | Flag parsed/stored but behavior incomplete | | ⚠️ Partial | 1 | Flag parsed/stored but behavior incomplete |
| ❌ Not Implemented | 62 | Flag not recognized or no behavior | | ❌ Not Implemented | 98 | Flag not recognized or no behavior |
| **Total** | **136** | | | **Total** | **136** | |
--- ---
@@ -20,31 +20,31 @@ This document maps rsync's full feature set to FastSync's current implementation
|------|-------------------|-----------------|-------| |------|-------------------|-----------------|-------|
| `-a`, `--archive` | Archive mode is -rlptgoD | 🔀 Alt Arg | Maps to -c -m -M (compression + multithread + metadata) | | `-a`, `--archive` | Archive mode is -rlptgoD | 🔀 Alt Arg | Maps to -c -m -M (compression + multithread + metadata) |
| `-v`, `--verbose` | Increase verbosity | ✅ Implemented | Sets `log_level=DEBUG` | | `-v`, `--verbose` | Increase verbosity | ✅ Implemented | Sets `log_level=DEBUG` |
| `-q`, `--quiet` | Suppress non-error messages | Implemented | `quiet` config field | | `-q`, `--quiet` | Suppress non-error messages | ❌ Not Implemented | Removed because it had no effect |
| `-h`, `--help` | Show help | ✅ Implemented | Prints usage and exits | | `--help` | Show help | ✅ Implemented | Prints usage and exits; `-h` is not accepted |
| `-V`, `--version` | Print version | ❌ Not Implemented | | | `-V`, `--version` | Print version | Implemented | |
| `--info=FLAGS` | Fine-grained info verbosity | ⚠️ Partial | `info_level` stored, not wired | | `--info=FLAGS` | Fine-grained info verbosity | ❌ Not Implemented | Removed because it had no effect |
| `--debug=FLAGS` | Fine-grained debug verbosity | ⚠️ Partial | `debug_level` stored, not wired | | `--debug=FLAGS` | Fine-grained debug verbosity | ❌ Not Implemented | Removed because it had no effect |
| `--stderr=MODE` | Change stderr output mode | ❌ Not Implemented | | | `--stderr=MODE` | Change stderr output mode | ❌ Not Implemented | |
| `--no-motd` | Suppress daemon MOTD | ❌ Not Implemented | | | `--no-motd` | Suppress daemon MOTD | ❌ Not Implemented | |
| `--exclude=PATTERN` | Exclude files matching pattern | ✅ Implemented | Glob matching in scanner | | `--exclude=PATTERN` | Exclude files matching pattern | ✅ Implemented | Glob matching in scanner |
| `--include=PATTERN` | Include files matching pattern | ✅ Implemented | Glob matching in scanner | | `--include=PATTERN` | Include files matching pattern | ✅ Implemented | Glob matching in scanner |
| `-C`, `--cvs-exclude` | Auto-ignore CVS files | ⚠️ Partial | `cvs_exclude` stored, not wired | | `-C`, `--cvs-exclude` | Auto-ignore CVS files | ❌ Not Implemented | Removed because it had no effect |
## 2. Modifying Output ## 2. Modifying Output
| Flag | Rsync Description | FastSync Status | Notes | | Flag | Rsync Description | FastSync Status | Notes |
|------|-------------------|-----------------|-------| |------|-------------------|-----------------|-------|
| `--stats` | Give transfer stats | ✅ Implemented | Prints file/byte counts | | `--stats` | Give transfer stats | ✅ Implemented | Prints file/byte counts |
| `-h`, `--human-readable` | Human-readable numbers | ⚠️ Partial | `human_readable` stored, not wired | | `-h`, `--human-readable` | Human-readable numbers | ❌ Not Implemented | Removed because it had no effect |
| `-i`, `--itemize-changes` | Per-file change summary | ⚠️ Partial | `itemize_changes` stored, not wired | | `-i`, `--itemize-changes` | Per-file change summary | ❌ Not Implemented | Removed because it had no effect |
| `--progress` | Show progress | ✅ Implemented | Progress callback in sender | | `--progress` | Show progress | ✅ Implemented | Progress callback in sender |
| `-P` | Same as --partial --progress | ❌ Not Implemented | | | `-P` | Same as --partial --progress | ❌ Not Implemented | |
| `--out-format=FORMAT` | Custom output format | ⚠️ Partial | `out_format` stored, not wired | | `--out-format=FORMAT` | Custom output format | ❌ Not Implemented | Removed because it had no effect |
| `--log-file=FILE` | Log to file | ✅ Implemented | `log_file` config field | | `--log-file=FILE` | Log to file | ✅ Implemented | `log_file` config field |
| `--log-file-format=FMT` | Log format | ❌ Not Implemented | | | `--log-file-format=FMT` | Log format | ❌ Not Implemented | |
| `--8-bit-output` | Leave high-bit chars unescaped | ❌ Not Implemented | | | `--8-bit-output` | Leave high-bit chars unescaped | ❌ Not Implemented | |
| `--list-only` | List files instead of copying | ⚠️ Partial | `list_only` stored, not wired | | `--list-only` | List files instead of copying | ❌ Not Implemented | Removed because it had no effect |
## 3. File Selection ## 3. File Selection
@@ -52,8 +52,8 @@ This document maps rsync's full feature set to FastSync's current implementation
|------|-------------------|-----------------|-------| |------|-------------------|-----------------|-------|
| `--exclude-from=FILE` | Read exclude patterns from file | ✅ Implemented | Reads patterns from file | | `--exclude-from=FILE` | Read exclude patterns from file | ✅ Implemented | Reads patterns from file |
| `--include-from=FILE` | Read include patterns from file | ✅ Implemented | Reads patterns from file | | `--include-from=FILE` | Read include patterns from file | ✅ Implemented | Reads patterns from file |
| `--filter=RULE` | Add file-filtering rule | ⚠️ Partial | `filters` ArrayList stored, not wired | | `--filter=RULE` | Add file-filtering rule | ❌ Not Implemented | Removed because it had no effect |
| `--files-from=FILE` | Read source file list from file | ⚠️ Partial | `files_from` stored, not wired | | `--files-from=FILE` | Read source file list from file | ❌ Not Implemented | Removed because it had no effect |
| `-0`, `--from0` | Delimit *-from files with NULs | ❌ Not Implemented | | | `-0`, `--from0` | Delimit *-from files with NULs | ❌ Not Implemented | |
| `--max-size=SIZE` | Skip files larger than SIZE | ✅ Implemented | `max_size` in scanner | | `--max-size=SIZE` | Skip files larger than SIZE | ✅ Implemented | `max_size` in scanner |
| `--min-size=SIZE` | Skip files smaller than SIZE | ✅ Implemented | `min_size` in scanner | | `--min-size=SIZE` | Skip files smaller than SIZE | ✅ Implemented | `min_size` in scanner |
@@ -69,7 +69,7 @@ This document maps rsync's full feature set to FastSync's current implementation
| Flag | Rsync Description | FastSync Status | Notes | | Flag | Rsync Description | FastSync Status | Notes |
|------|-------------------|-----------------|-------| |------|-------------------|-----------------|-------|
| `-r`, `--recursive` | Recurse into directories | ✅ Implemented | Default behavior | | `-r`, `--recursive` | Recurse into directories | ✅ Implemented | Default behavior |
| `-R`, `--relative` | Use relative path names | ⚠️ Partial | `relative` stored, not wired | | `-R`, `--relative` | Use relative path names | ❌ Not Implemented | Removed because it had no effect |
| `--no-implied-dirs` | Don't send implied dirs with -R | ❌ Not Implemented | | | `--no-implied-dirs` | Don't send implied dirs with -R | ❌ Not Implemented | |
| `-d`, `--dirs` | Transfer dirs without recursing | ❌ Not Implemented | | | `-d`, `--dirs` | Transfer dirs without recursing | ❌ Not Implemented | |
| `--mkpath` | Create missing path components | ❌ Not Implemented | | | `--mkpath` | Create missing path components | ❌ Not Implemented | |
@@ -78,10 +78,10 @@ This document maps rsync's full feature set to FastSync's current implementation
| Flag | Rsync Description | FastSync Status | Notes | | Flag | Rsync Description | FastSync Status | Notes |
|------|-------------------|-----------------|-------| |------|-------------------|-----------------|-------|
| `-u`, `--update` | Skip files newer on receiver | ⚠️ Partial | `update` stored, not wired | | `-u`, `--update` | Skip files newer on receiver | ❌ Not Implemented | Removed because it had no effect |
| `--inplace` | Update files in-place | ✅ Implemented | Direct write mode | | `--inplace` | Update files in-place | ✅ Implemented | Direct write mode |
| `--append` | Append data to shorter files | ⚠️ Partial | `append` stored, not wired | | `--append` | Append data to shorter files | ❌ Not Implemented | Removed because it had no effect |
| `--append-verify` | Append with old-data checksum | ⚠️ Partial | `append_verify` stored, not wired | | `--append-verify` | Append with old-data checksum | ❌ Not Implemented | Removed because it had no effect |
| `-W`, `--whole-file` | Copy whole file (no delta) | ❌ Not Implemented | | | `-W`, `--whole-file` | Copy whole file (no delta) | ❌ Not Implemented | |
| `--block-size=SIZE` | Force checksum block-size | ⚠️ Partial | Parsed as `--delta-block`; controls delta transfer block size | | `--block-size=SIZE` | Force checksum block-size | ⚠️ Partial | Parsed as `--delta-block`; controls delta transfer block size |
@@ -100,15 +100,15 @@ This document maps rsync's full feature set to FastSync's current implementation
| Flag | Rsync Description | FastSync Status | Notes | | Flag | Rsync Description | FastSync Status | Notes |
|------|-------------------|-----------------|-------| |------|-------------------|-----------------|-------|
| `--delete` | Delete extraneous files from dest | ✅ Implemented | `use_delete` config field | | `--delete` | Delete extraneous files from dest | ✅ Implemented | `use_delete` config field |
| `--delete-before` | Delete before transfer | ⚠️ Partial | `delete_before` stored, not wired | | `--delete-before` | Delete before transfer | ❌ Not Implemented | Removed because it had no effect |
| `--delete-during` | Delete during transfer | ❌ Not Implemented | | | `--delete-during` | Delete during transfer | ❌ Not Implemented | |
| `--delete-delay` | Find deletions during, delete after | ❌ Not Implemented | | | `--delete-delay` | Find deletions during, delete after | ❌ Not Implemented | |
| `--delete-after` | Delete after transfer | ⚠️ Partial | `delete_after` stored, not wired | | `--delete-after` | Delete after transfer | ❌ Not Implemented | Removed because it had no effect |
| `--delete-excluded` | Also delete excluded files | ⚠️ Partial | `delete_excluded` stored, not wired | | `--delete-excluded` | Also delete excluded files | ❌ Not Implemented | Removed because it had no effect |
| `--max-delete=NUM` | Max files to delete | ⚠️ Partial | `max_delete` stored, not wired | | `--max-delete=NUM` | Max files to delete | ❌ Not Implemented | Removed because it had no effect |
| `--ignore-errors` | Delete even with I/O errors | ❌ Not Implemented | | | `--ignore-errors` | Delete even with I/O errors | ❌ Not Implemented | |
| `--force` | Force deletion of non-empty dirs | ❌ Not Implemented | | | `--force` | Force deletion of non-empty dirs | ❌ Not Implemented | |
| `--prune-empty-dirs` | Prune empty dir chains | ⚠️ Partial | `prune_empty_dirs` stored, not wired | | `--prune-empty-dirs` | Prune empty dir chains | ❌ Not Implemented | Removed because it had no effect |
## 8. Metadata Preservation ## 8. Metadata Preservation
@@ -121,11 +121,11 @@ This document maps rsync's full feature set to FastSync's current implementation
| `-t`, `--times` | Preserve modification times | ✅ Implemented | Part of -M | | `-t`, `--times` | Preserve modification times | ✅ Implemented | Part of -M |
| `-E`, `--executability` | Preserve executability | ❌ Not Implemented | | | `-E`, `--executability` | Preserve executability | ❌ Not Implemented | |
| `--chmod=CHMOD` | Affect file permissions | ❌ Not Implemented | | | `--chmod=CHMOD` | Affect file permissions | ❌ Not Implemented | |
| `-A`, `--acls` | Preserve ACLs | ⚠️ Partial | `preserve_acls` stored, not wired | | `-A`, `--acls` | Preserve ACLs | ❌ Not Implemented | Removed because it had no effect |
| `-X`, `--xattrs` | Preserve extended attributes | ⚠️ Partial | `preserve_xattrs` stored, not wired | | `-X`, `--xattrs` | Preserve extended attributes | ❌ Not Implemented | Removed because it had no effect |
| `-H`, `--hard-links` | Preserve hard links | ⚠️ Partial | `preserve_hard_links` stored, not wired | | `-H`, `--hard-links` | Preserve hard links | ❌ Not Implemented | Removed because it had no effect |
| `-D` | Same as --devices --specials | 🔀 Alt Arg | Maps to --devices only (no --specials) | | `-D` | Same as --devices --specials | ❌ Not Implemented | Removed because device-file handling is not implemented |
| `--devices` | Preserve device files | ⚠️ Partial | `preserve_devices` stored, not wired | | `--devices` | Preserve device files | ❌ Not Implemented | Removed because it had no effect |
| `--specials` | Preserve special files | ❌ Not Implemented | | | `--specials` | Preserve special files | ❌ Not Implemented | |
| `--copy-devices` | Copy device contents as file | ❌ Not Implemented | | | `--copy-devices` | Copy device contents as file | ❌ Not Implemented | |
| `--write-devices` | Write to devices as files | ❌ Not Implemented | | | `--write-devices` | Write to devices as files | ❌ Not Implemented | |
@@ -159,11 +159,11 @@ This document maps rsync's full feature set to FastSync's current implementation
| Flag | Rsync Description | FastSync Status | Notes | | Flag | Rsync Description | FastSync Status | Notes |
|------|-------------------|-----------------|-------| |------|-------------------|-----------------|-------|
| `-c`, `--checksum` | Skip based on checksum | 🔀 Alt Arg | `-c` means compression; `--checksum` stored and forwarded to scanner | | `--checksum` | Skip based on checksum | ❌ Not Implemented | Removed because it had no effect; `-c` means compression |
| `--checksum-choice=STR` | Choose checksum algorithm | ❌ Not Implemented | xxHash used internally | | `--checksum-choice=STR` | Choose checksum algorithm | ❌ Not Implemented | xxHash used internally |
| `--compare-dest=DIR` | Compare dest files relative to DIR | ⚠️ Partial | `compare_dest` stored, not wired | | `--compare-dest=DIR` | Compare dest files relative to DIR | ❌ Not Implemented | Removed because it had no effect |
| `--copy-dest=DIR` | Include copies of unchanged files | ⚠️ Partial | `copy_dest` stored, not wired | | `--copy-dest=DIR` | Include copies of unchanged files | ❌ Not Implemented | Removed because it had no effect |
| `--link-dest=DIR` | Hardlink to files when unchanged | ⚠️ Partial | `link_dest` stored, not wired | | `--link-dest=DIR` | Hardlink to files when unchanged | ❌ Not Implemented | Removed because it had no effect |
| `--fuzzy`, `--no-fuzzy` | Find similar file for basis | ❌ Not Implemented | | | `--fuzzy`, `--no-fuzzy` | Find similar file for basis | ❌ Not Implemented | |
## 12. Compression ## 12. Compression
@@ -171,7 +171,7 @@ This document maps rsync's full feature set to FastSync's current implementation
| Flag | Rsync Description | FastSync Status | Notes | | Flag | Rsync Description | FastSync Status | Notes |
|------|-------------------|-----------------|-------| |------|-------------------|-----------------|-------|
| `-z`, `--compress` | Compress file data | 🔀 Alt Arg | Always uses zstd (rsync supports multiple algorithms) | | `-z`, `--compress` | Compress file data | 🔀 Alt Arg | Always uses zstd (rsync supports multiple algorithms) |
| `--compress-choice=STR` | Choose compression algorithm | ⚠️ Partial | `compress_choice` stored, always zstd | | `--compress-choice=STR` | Choose compression algorithm | ❌ Not Implemented | Removed because it had no effect; FastSync always uses zstd |
| `--compress-level=NUM` | Set compression level | ✅ Implemented | 1-22, default 5 | | `--compress-level=NUM` | Set compression level | ✅ Implemented | 1-22, default 5 |
| `--compress-threads=NUM` | Set compression threads | ❌ Not Implemented | | | `--compress-threads=NUM` | Set compression threads | ❌ Not Implemented | |
| `--skip-compress=LIST` | Skip compress for suffixes | ❌ Not Implemented | Internal skip for hardcoded types; not user-configurable | | `--skip-compress=LIST` | Skip compress for suffixes | ❌ Not Implemented | Internal skip for hardcoded types; not user-configurable |
@@ -180,22 +180,22 @@ This document maps rsync's full feature set to FastSync's current implementation
| Flag | Rsync Description | FastSync Status | Notes | | Flag | Rsync Description | FastSync Status | Notes |
|------|-------------------|-----------------|-------| |------|-------------------|-----------------|-------|
| `-e`, `--rsh=COMMAND` | Remote shell to use | Implemented | SSH transport support | | `-e`, `--rsh=COMMAND` | Remote shell to use | ❌ Not Implemented | Removed; SSH invokes `ssh` directly |
| `--rsync-path=PROGRAM` | rsync binary on remote | Implemented | `rsync_path` config field | | `--rsync-path=PROGRAM` | rsync binary on remote | ❌ Not Implemented | Removed; use `--fastsync-server-path` |
| `--port=PORT` | Alternate daemon port | ✅ Implemented | `server_port` config field | | `--port=PORT` | Alternate daemon port | ✅ Implemented | `server_port` config field |
| `--sockopts=OPTIONS` | Custom TCP options | ❌ Not Implemented | | | `--sockopts=OPTIONS` | Custom TCP options | ❌ Not Implemented | |
| `--blocking-io` | Use blocking I/O for remote shell | ❌ Not Implemented | | | `--blocking-io` | Use blocking I/O for remote shell | ❌ Not Implemented | |
| `--outbuf=N\|L\|B` | Set output buffering | ❌ Not Implemented | | | `--outbuf=N\|L\|B` | Set output buffering | ❌ Not Implemented | |
| `--address=ADDRESS` | Bind address for outgoing socket | Implemented | `address` config field | | `--address=ADDRESS` | Bind address for outgoing socket | ❌ Not Implemented | Removed because it had no effect |
| `-4`, `--ipv4` | Prefer IPv4 | Implemented | `ipv4` config field | | `-4`, `--ipv4` | Prefer IPv4 | ❌ Not Implemented | Removed because it had no effect |
| `-6`, `--ipv6` | Prefer IPv6 | Implemented | `ipv6` config field | | `-6`, `--ipv6` | Prefer IPv6 | ❌ Not Implemented | Removed because it had no effect |
## 14. Daemon Mode ## 14. Daemon Mode
| Flag | Rsync Description | FastSync Status | Notes | | Flag | Rsync Description | FastSync Status | Notes |
|------|-------------------|-----------------|-------| |------|-------------------|-----------------|-------|
| `--daemon` | Run as rsync daemon | ⚠️ Partial | `daemon` stored, not wired | | `--daemon` | Run as rsync daemon | ❌ Not Implemented | Removed because it had no effect |
| `--config=FILE` | Alternate rsyncd.conf file | ⚠️ Partial | `daemon_config` stored, not wired | | `--config=FILE` | Alternate rsyncd.conf file | ❌ Not Implemented | Removed because it had no effect |
| `--dparam=OVERRIDE` | Override global daemon config | ❌ Not Implemented | | | `--dparam=OVERRIDE` | Override global daemon config | ❌ Not Implemented | |
| `--no-detach` | Don't detach from parent | ❌ Not Implemented | | | `--no-detach` | Don't detach from parent | ❌ Not Implemented | |
| `--password-file=FILE` | Read daemon password from file | ❌ Not Implemented | | | `--password-file=FILE` | Read daemon password from file | ❌ Not Implemented | |
@@ -266,7 +266,6 @@ Ranked by user demand, implementation complexity, and interoperability impact:
| `-f` / `--sendfile` | Zero-copy sendfile() syscall (TCP only) | | `-f` / `--sendfile` | Zero-copy sendfile() syscall (TCP only) |
| `-c [level]` | zstd compression level (1-22) | | `-c [level]` | zstd compression level (1-22) |
| `--chunk-size` | Configurable chunk size | | `--chunk-size` | Configurable chunk size |
| `--queue-size` | Pipeline queue capacity |
| `--tls` | TLS encryption (mutual auth) | | `--tls` | TLS encryption (mutual auth) |
| `--fastsync-server-path` | Path to fastsync-server binary | | `--fastsync-server-path` | Path to fastsync-server binary |
| `--server-host` / `--server-port` | Direct TCP connection | | `--server-host` / `--server-port` | Direct TCP connection |
+8 -107
View File
@@ -104,7 +104,7 @@ int parse_args(Config* config, int argc, char* argv[], int* positional_args,
} else if (strcmp(argv[i], "-n") == 0 || strcmp(argv[i], "--dry-run") == 0) { } else if (strcmp(argv[i], "-n") == 0 || strcmp(argv[i], "--dry-run") == 0) {
config->dry_run = true; config->dry_run = true;
} else if (strcmp(argv[i], "-p") == 0 && i + 1 < argc) { } else if (strcmp(argv[i], "-p") == 0 && i + 1 < argc) {
if (!set_positive_int_option(&config->ssh_port, argv[++i], "-p")) if (set_positive_int_option(&config->ssh_port, argv[++i], "-p") != 0)
return -1; return -1;
if (config->ssh_port > 65535) { if (config->ssh_port > 65535) {
log_message(LOG_LEVEL_ERROR, "SSH port must be 1-65535\n"); log_message(LOG_LEVEL_ERROR, "SSH port must be 1-65535\n");
@@ -139,8 +139,14 @@ int parse_args(Config* config, int argc, char* argv[], int* positional_args,
} }
config->include_patterns[config->include_count++] = dup; config->include_patterns[config->include_count++] = dup;
} else if (strcmp(argv[i], "--max-size") == 0 && i + 1 < argc) { } else if (strcmp(argv[i], "--max-size") == 0 && i + 1 < argc) {
if (!set_nonneg_int_option(&config->max_size, argv[++i], "Max Size")) char* end;
errno = 0;
unsigned long long val = strtoull(argv[++i], &end, 10);
if (errno != 0 || *end != '\0') {
fprintf(stderr, "Error: --max-size must be a non-negative integer\n");
return -1; return -1;
}
config->max_size = val;
} else if (strcmp(argv[i], "--min-size") == 0 && i + 1 < argc) { } else if (strcmp(argv[i], "--min-size") == 0 && i + 1 < argc) {
char* end; char* end;
errno = 0; errno = 0;
@@ -268,9 +274,6 @@ int parse_args(Config* config, int argc, char* argv[], int* positional_args,
} else if (strcmp(argv[i], "--contimeout") == 0 && i + 1 < argc) { } else if (strcmp(argv[i], "--contimeout") == 0 && i + 1 < argc) {
if (set_positive_int_option(&config->contimeout, argv[++i], "--contimeout") != 0) if (set_positive_int_option(&config->contimeout, argv[++i], "--contimeout") != 0)
return -1; return -1;
} else if (strcmp(argv[i], "-q") == 0 || strcmp(argv[i], "--quiet") == 0 ||
strcmp(argv[i], "--silent") == 0) {
config->quiet = true;
} else if (strcmp(argv[i], "--backup") == 0) { } else if (strcmp(argv[i], "--backup") == 0) {
config->backup = true; config->backup = true;
} else if (strcmp(argv[i], "--backup-dir") == 0 && i + 1 < argc) { } else if (strcmp(argv[i], "--backup-dir") == 0 && i + 1 < argc) {
@@ -294,9 +297,6 @@ int parse_args(Config* config, int argc, char* argv[], int* positional_args,
} }
config->log_file = lf; config->log_file = lf;
log_set_file(lf); log_set_file(lf);
} else if (strcmp(argv[i], "--queue-size") == 0 && i + 1 < argc) {
if (set_positive_int_option(&config->queue_size, argv[++i], "--queue-size") != 0)
return -1;
} else if (strcmp(argv[i], "--exclude-from") == 0 && i + 1 < argc) { } else if (strcmp(argv[i], "--exclude-from") == 0 && i + 1 < argc) {
if (read_patterns_from_file(argv[++i], &config->exclude_patterns, &config->exclude_count) != if (read_patterns_from_file(argv[++i], &config->exclude_patterns, &config->exclude_count) !=
0) 0)
@@ -321,118 +321,19 @@ int parse_args(Config* config, int argc, char* argv[], int* positional_args,
config->safe_links = true; config->safe_links = true;
} else if (strcmp(argv[i], "--copy-unsafe-links") == 0) { } else if (strcmp(argv[i], "--copy-unsafe-links") == 0) {
config->copy_unsafe_links = true; config->copy_unsafe_links = true;
} else if (strcmp(argv[i], "-H") == 0 || strcmp(argv[i], "--hard-links") == 0) {
config->preserve_hard_links = true;
} else if (strcmp(argv[i], "-A") == 0 || strcmp(argv[i], "--acls") == 0) {
config->preserve_acls = true;
} else if (strcmp(argv[i], "-X") == 0 || strcmp(argv[i], "--xattrs") == 0) {
config->preserve_xattrs = true;
} else if (strcmp(argv[i], "-D") == 0 || strcmp(argv[i], "--devices") == 0) {
config->preserve_devices = true;
} else if (strcmp(argv[i], "-S") == 0 || strcmp(argv[i], "--sparse") == 0) { } else if (strcmp(argv[i], "-S") == 0 || strcmp(argv[i], "--sparse") == 0) {
config->preserve_sparse = true; config->preserve_sparse = true;
} else if (strcmp(argv[i], "-i") == 0 || strcmp(argv[i], "--itemize-changes") == 0) {
config->itemize_changes = true;
} else if (strcmp(argv[i], "--out-format") == 0 && i + 1 < argc) {
if (set_string_option(&config->out_format, argv[++i], "--out-format") != 0)
return -1;
} else if (strcmp(argv[i], "--info") == 0 && i + 1 < argc) {
if (set_nonneg_int_option(&config->info_level, argv[++i], "--info") != 0)
return -1;
} else if (strcmp(argv[i], "--debug") == 0 && i + 1 < argc) {
if (set_nonneg_int_option(&config->debug_level, argv[++i], "--debug") != 0)
return -1;
} else if (strcmp(argv[i], "--list-only") == 0) {
config->list_only = true;
} else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--human-readable") == 0) {
config->human_readable = true;
} else if (strcmp(argv[i], "-u") == 0 || strcmp(argv[i], "--update") == 0) {
config->update = true;
} else if (strcmp(argv[i], "--inplace") == 0) { } else if (strcmp(argv[i], "--inplace") == 0) {
config->inplace = true; config->inplace = true;
} else if (strcmp(argv[i], "--append") == 0) {
config->append = true;
} else if (strcmp(argv[i], "--append-verify") == 0) {
config->append_verify = true;
} else if (strcmp(argv[i], "--delete-excluded") == 0) {
config->delete_excluded = true;
} else if (strcmp(argv[i], "--delete-after") == 0) {
config->delete_after = true;
} else if (strcmp(argv[i], "--max-delete") == 0 && i + 1 < argc) {
if (set_nonneg_int_option(&config->max_delete, argv[++i], "--max-delete") != 0)
return -1;
} else if (strcmp(argv[i], "--filter") == 0 && i + 1 < argc) {
if (!config->filters)
config->filters = array_list_create(free);
char* dup = str_dup(argv[++i]);
if (!dup)
return -1;
array_list_add(config->filters, dup);
} else if (strcmp(argv[i], "--files-from") == 0 && i + 1 < argc) {
if (set_string_option(&config->files_from, argv[++i], "--files-from") != 0)
return -1;
} else if (strcmp(argv[i], "--cvs-exclude") == 0) {
config->cvs_exclude = true;
} else if (strcmp(argv[i], "--prune-empty-dirs") == 0) {
config->prune_empty_dirs = true;
} else if (strcmp(argv[i], "-R") == 0 || strcmp(argv[i], "--relative") == 0) {
config->relative = true;
} else if (strcmp(argv[i], "-e") == 0 || strcmp(argv[i], "--rsh") == 0) {
if (i + 1 < argc) {
if (set_string_option(&config->rsh_command, argv[++i], "-e/--rsh") != 0)
return -1;
} else {
fprintf(stderr, "Error: -e/--rsh requires a command argument\n");
return -1;
}
} else if (strcmp(argv[i], "--rsync-path") == 0 && i + 1 < argc) {
if (set_string_option(&config->rsync_path, argv[++i], "--rsync-path") != 0)
return -1;
} else if (strcmp(argv[i], "--temp-dir") == 0 && i + 1 < argc) {
if (set_string_option(&config->temp_dir, argv[++i], "--temp-dir") != 0)
return -1;
} else if (strcmp(argv[i], "--compare-dest") == 0 && i + 1 < argc) {
if (set_string_option(&config->compare_dest, argv[++i], "--compare-dest") != 0)
return -1;
} else if (strcmp(argv[i], "--copy-dest") == 0 && i + 1 < argc) {
if (set_string_option(&config->copy_dest, argv[++i], "--copy-dest") != 0)
return -1;
} else if (strcmp(argv[i], "--link-dest") == 0 && i + 1 < argc) {
if (set_string_option(&config->link_dest, argv[++i], "--link-dest") != 0)
return -1;
} else if (strcmp(argv[i], "--partial-dir") == 0 && i + 1 < argc) { } else if (strcmp(argv[i], "--partial-dir") == 0 && i + 1 < argc) {
if (set_string_option(&config->partial_dir, argv[++i], "--partial-dir") != 0) if (set_string_option(&config->partial_dir, argv[++i], "--partial-dir") != 0)
return -1; return -1;
} else if (strcmp(argv[i], "--suffix") == 0 && i + 1 < argc) { } else if (strcmp(argv[i], "--suffix") == 0 && i + 1 < argc) {
if (set_string_option(&config->suffix, argv[++i], "--suffix") != 0) if (set_string_option(&config->suffix, argv[++i], "--suffix") != 0)
return -1; return -1;
} else if (strcmp(argv[i], "--delete-before") == 0) {
config->delete_before = true;
} else if (strcmp(argv[i], "-T") == 0 && i + 1 < argc) { } else if (strcmp(argv[i], "-T") == 0 && i + 1 < argc) {
if (set_positive_int_option(&config->timeout, argv[++i], "-T") != 0) if (set_positive_int_option(&config->timeout, argv[++i], "-T") != 0)
return -1; return -1;
} else if (strcmp(argv[i], "--address") == 0 && i + 1 < argc) {
if (set_string_option(&config->address, argv[++i], "--address") != 0)
return -1;
} else if (strcmp(argv[i], "--bind-address") == 0 && i + 1 < argc) {
if (set_string_option(&config->bind_address, argv[++i], "--bind-address") != 0)
return -1;
} else if (strcmp(argv[i], "--ipv6") == 0) {
config->ipv6 = true;
} else if (strcmp(argv[i], "--ipv4") == 0) {
config->ipv4 = true;
} else if (strcmp(argv[i], "--daemon") == 0) {
config->daemon = true;
} else if (strcmp(argv[i], "--config") == 0 && i + 1 < argc) {
if (set_string_option(&config->daemon_config, argv[++i], "--config") != 0)
return -1;
} else if (strcmp(argv[i], "--server") == 0) {
config->server_mode = true;
} else if (strcmp(argv[i], "--checksum") == 0) {
config->checksum = true;
} else if (strcmp(argv[i], "--compress-choice") == 0 && i + 1 < argc) {
if (set_string_option(&config->compress_choice, argv[++i], "--compress-choice") != 0)
return -1;
} else if (strcmp(argv[i], "--compress-level") == 0 && i + 1 < argc) { } else if (strcmp(argv[i], "--compress-level") == 0 && i + 1 < argc) {
if (set_positive_int_option(&config->compression_level, argv[++i], "--compress-level") != 0) if (set_positive_int_option(&config->compression_level, argv[++i], "--compress-level") != 0)
return -1; return -1;
+3 -4
View File
@@ -34,7 +34,7 @@ static int send_dry_run_manifest(Config* config) {
config->send_directory, config->use_metadata, config->chunk_size, config->exclude_patterns, config->send_directory, config->use_metadata, config->chunk_size, config->exclude_patterns,
config->exclude_count, config->include_patterns, config->include_count, config->max_size, config->exclude_count, config->include_patterns, config->include_count, config->max_size,
config->min_size, config->max_depth, config->follow_symlinks, config->copy_links, config->min_size, config->max_depth, config->follow_symlinks, config->copy_links,
config->safe_links, config->copy_unsafe_links, config->checksum); config->safe_links, config->copy_unsafe_links);
if (!scanner) if (!scanner)
return -1; return -1;
Chunk* chunk; Chunk* chunk;
@@ -375,8 +375,7 @@ static int scan_directory_multithreaded(void* pipeline_context) {
context->config->exclude_patterns, context->config->exclude_count, context->config->exclude_patterns, context->config->exclude_count,
context->config->include_patterns, context->config->include_count, context->config->max_size, context->config->include_patterns, context->config->include_count, context->config->max_size,
context->config->min_size, context->config->max_depth, 4, context->config->follow_symlinks, context->config->min_size, context->config->max_depth, 4, context->config->follow_symlinks,
context->config->copy_links, context->config->safe_links, context->config->copy_unsafe_links, context->config->copy_links, context->config->safe_links, context->config->copy_unsafe_links);
context->config->checksum);
Chunk* current_chunk; Chunk* current_chunk;
while ((current_chunk = parallel_scanner_next(scanner)) != NULL) { while ((current_chunk = parallel_scanner_next(scanner)) != NULL) {
@@ -540,7 +539,7 @@ int send_files(Config* config) {
config->send_directory, config->use_metadata, config->chunk_size, config->exclude_patterns, config->send_directory, config->use_metadata, config->chunk_size, config->exclude_patterns,
config->exclude_count, config->include_patterns, config->include_count, config->max_size, config->exclude_count, config->include_patterns, config->include_count, config->max_size,
config->min_size, config->max_depth, config->follow_symlinks, config->copy_links, config->min_size, config->max_depth, config->follow_symlinks, config->copy_links,
config->safe_links, config->copy_unsafe_links, config->checksum); config->safe_links, config->copy_unsafe_links);
Chunk* current_chunk; Chunk* current_chunk;
unsigned long long total_bytes = 0; unsigned long long total_bytes = 0;
int total_files = 0; int total_files = 0;
+3 -6
View File
@@ -44,7 +44,7 @@ DirectoryScanner* directory_scanner_create(const char* root_directory, bool use_
int include_count, unsigned long long max_size, int include_count, unsigned long long max_size,
unsigned long long min_size, int max_depth, unsigned long long min_size, int max_depth,
bool follow_symlinks, bool copy_links, bool safe_links, bool follow_symlinks, bool copy_links, bool safe_links,
bool copy_unsafe_links, bool checksum) { bool copy_unsafe_links) {
DirectoryScanner* scanner = malloc(sizeof(DirectoryScanner)); DirectoryScanner* scanner = malloc(sizeof(DirectoryScanner));
if (scanner == NULL) if (scanner == NULL)
return NULL; return NULL;
@@ -65,7 +65,6 @@ DirectoryScanner* directory_scanner_create(const char* root_directory, bool use_
scanner->copy_links = copy_links; scanner->copy_links = copy_links;
scanner->safe_links = safe_links; scanner->safe_links = safe_links;
scanner->copy_unsafe_links = copy_unsafe_links; scanner->copy_unsafe_links = copy_unsafe_links;
scanner->checksum = checksum;
DirEntry* root = dir_entry_create(root_directory, 0); DirEntry* root = dir_entry_create(root_directory, 0);
if (!root) { if (!root) {
queue_destroy(scanner->directories); queue_destroy(scanner->directories);
@@ -292,7 +291,6 @@ typedef struct {
bool copy_links; bool copy_links;
bool safe_links; bool safe_links;
bool copy_unsafe_links; bool copy_unsafe_links;
bool checksum;
} ParallelWorkerArg; } ParallelWorkerArg;
static int parallel_worker_thread(void* arg) { static int parallel_worker_thread(void* arg) {
@@ -301,7 +299,7 @@ static int parallel_worker_thread(void* arg) {
DirectoryScanner* ds = directory_scanner_create( DirectoryScanner* ds = directory_scanner_create(
wa->dirs[i], wa->use_metadata, wa->chunk_size, wa->exclude_patterns, wa->exclude_count, wa->dirs[i], wa->use_metadata, wa->chunk_size, wa->exclude_patterns, wa->exclude_count,
wa->include_patterns, wa->include_count, wa->max_size, wa->min_size, wa->max_depth, wa->include_patterns, wa->include_count, wa->max_size, wa->min_size, wa->max_depth,
wa->follow_symlinks, wa->copy_links, wa->safe_links, wa->copy_unsafe_links, wa->checksum); wa->follow_symlinks, wa->copy_links, wa->safe_links, wa->copy_unsafe_links);
Chunk* chunk; Chunk* chunk;
while ((chunk = directory_scanner_next(ds)) != NULL) { while ((chunk = directory_scanner_next(ds)) != NULL) {
queue_enqueue_multithreaded(wa->ps->result_queue, chunk, &wa->ps->result_mutex, queue_enqueue_multithreaded(wa->ps->result_queue, chunk, &wa->ps->result_mutex,
@@ -329,7 +327,7 @@ ParallelScanner* parallel_scanner_create(char* root_directory, bool use_metadata
int include_count, unsigned long long max_size, int include_count, unsigned long long max_size,
unsigned long long min_size, int max_depth, unsigned long long min_size, int max_depth,
int num_threads, bool follow_symlinks, bool copy_links, int num_threads, bool follow_symlinks, bool copy_links,
bool safe_links, bool copy_unsafe_links, bool checksum) { bool safe_links, bool copy_unsafe_links) {
ParallelScanner* ps = calloc(1, sizeof(ParallelScanner)); ParallelScanner* ps = calloc(1, sizeof(ParallelScanner));
if (!ps) if (!ps)
return NULL; return NULL;
@@ -562,7 +560,6 @@ ParallelScanner* parallel_scanner_create(char* root_directory, bool use_metadata
wa->copy_links = copy_links; wa->copy_links = copy_links;
wa->safe_links = safe_links; wa->safe_links = safe_links;
wa->copy_unsafe_links = copy_unsafe_links; wa->copy_unsafe_links = copy_unsafe_links;
wa->checksum = checksum;
start += count; start += count;
if (thrd_create(&ps->threads[t], parallel_worker_thread, wa) != thrd_success) { if (thrd_create(&ps->threads[t], parallel_worker_thread, wa) != thrd_success) {
for (int j = 0; j < count; j++) for (int j = 0; j < count; j++)
+2 -3
View File
@@ -25,7 +25,6 @@ typedef struct {
bool copy_links; bool copy_links;
bool safe_links; bool safe_links;
bool copy_unsafe_links; bool copy_unsafe_links;
bool checksum;
} DirectoryScanner; } DirectoryScanner;
typedef struct { typedef struct {
@@ -46,7 +45,7 @@ DirectoryScanner* directory_scanner_create(const char* root_directory, bool use_
int include_count, unsigned long long max_size, int include_count, unsigned long long max_size,
unsigned long long min_size, int max_depth, unsigned long long min_size, int max_depth,
bool follow_symlinks, bool copy_links, bool safe_links, bool follow_symlinks, bool copy_links, bool safe_links,
bool copy_unsafe_links, bool checksum); bool copy_unsafe_links);
Chunk* directory_scanner_next(DirectoryScanner* scanner); Chunk* directory_scanner_next(DirectoryScanner* scanner);
void directory_scanner_destroy(DirectoryScanner* scanner); void directory_scanner_destroy(DirectoryScanner* scanner);
@@ -56,7 +55,7 @@ ParallelScanner* parallel_scanner_create(char* root_directory, bool use_metadata
int include_count, unsigned long long max_size, int include_count, unsigned long long max_size,
unsigned long long min_size, int max_depth, unsigned long long min_size, int max_depth,
int num_threads, bool follow_symlinks, bool copy_links, int num_threads, bool follow_symlinks, bool copy_links,
bool safe_links, bool copy_unsafe_links, bool checksum); bool safe_links, bool copy_unsafe_links);
Chunk* parallel_scanner_next(ParallelScanner* scanner); Chunk* parallel_scanner_next(ParallelScanner* scanner);
void parallel_scanner_destroy(ParallelScanner* scanner); void parallel_scanner_destroy(ParallelScanner* scanner);
-40
View File
@@ -51,19 +51,12 @@ static __attribute__((unused)) void print_usage() {
printf(" --timeout <sec> I/O timeout in seconds (default: 30)\n"); printf(" --timeout <sec> I/O timeout in seconds (default: 30)\n");
printf(" -T <sec> Alias for --timeout\n"); printf(" -T <sec> Alias for --timeout\n");
printf(" --contimeout <sec> Connection timeout in seconds (default: 10)\n"); printf(" --contimeout <sec> Connection timeout in seconds (default: 10)\n");
printf(" --address <host> Server hostname/IP to connect to\n");
printf(" --bind-address <ip> Bind to specific local address\n");
printf(" --ipv6 Prefer IPv6 connections\n");
printf(" --ipv4 Prefer IPv4 connections\n");
printf(" -q, --quiet Suppress non-error output\n");
printf(" --silent Alias for --quiet\n");
printf(" --backup Backup existing files before overwriting\n"); printf(" --backup Backup existing files before overwriting\n");
printf(" --backup-dir <dir> Directory for backups (requires --backup)\n"); printf(" --backup-dir <dir> Directory for backups (requires --backup)\n");
printf(" --suffix <str> Backup suffix (default: ~)\n"); printf(" --suffix <str> Backup suffix (default: ~)\n");
printf(" --stats Print transfer statistics at end\n"); printf(" --stats Print transfer statistics at end\n");
printf(" --max-depth <n> Maximum directory depth (0=unlimited)\n"); printf(" --max-depth <n> Maximum directory depth (0=unlimited)\n");
printf(" --log-file <path> Write log messages to file\n"); printf(" --log-file <path> Write log messages to file\n");
printf(" --queue-size <n> Queue capacity for multithreaded mode (default: 100)\n");
printf(" --partial Keep partial files on interrupted transfer\n"); printf(" --partial Keep partial files on interrupted transfer\n");
printf(" --partial-dir <dir> Directory for partial files\n"); printf(" --partial-dir <dir> Directory for partial files\n");
printf(" --fastsync-server-path <path>\n"); printf(" --fastsync-server-path <path>\n");
@@ -72,42 +65,9 @@ static __attribute__((unused)) void print_usage() {
printf(" --copy-links Transform symlinks into referent files\n"); printf(" --copy-links Transform symlinks into referent files\n");
printf(" --safe-links Skip symlinks that point outside transfer tree\n"); printf(" --safe-links Skip symlinks that point outside transfer tree\n");
printf(" --copy-unsafe-links Only transform unsafe symlinks into referent files\n"); printf(" --copy-unsafe-links Only transform unsafe symlinks into referent files\n");
printf(" -H, --hard-links Preserve hard links\n");
printf(" -A, --acls Preserve ACLs\n");
printf(" -X, --xattrs Preserve extended attributes\n");
printf(" -D, --devices Preserve device files\n");
printf(" -S, --sparse Handle sparse files efficiently\n"); printf(" -S, --sparse Handle sparse files efficiently\n");
printf(" -i, --itemize-changes Show per-file change summary\n");
printf(" --out-format <fmt> Custom output format string\n");
printf(" --info <flags> Info verbosity level\n");
printf(" --debug <flags> Debug verbosity level\n");
printf(" --list-only List files without transferring\n");
printf(" -h, --human-readable Human-readable numbers\n");
printf(" -u, --update Skip files newer on destination\n");
printf(" --inplace Update files in-place (no temp+rename)\n"); printf(" --inplace Update files in-place (no temp+rename)\n");
printf(" --append Append data to shorter files\n");
printf(" --append-verify Append with verify\n");
printf(" --delete-before Delete before transfer\n");
printf(" --delete-excluded Also delete excluded files\n");
printf(" --delete-after Delete after transfer, not before\n");
printf(" --max-delete <n> Maximum number of files to delete\n");
printf(" --filter <rule> Add file filtering rule\n");
printf(" --files-from <file> Read file list from file\n");
printf(" --cvs-exclude Auto-ignore CVS files\n");
printf(" --prune-empty-dirs Omit empty directories from transfer\n");
printf(" -R, --relative Use relative paths\n");
printf(" -e, --rsh <cmd> Specify remote shell\n");
printf(" --rsync-path <path> Path to remote binary\n");
printf(" --daemon Run in daemon mode\n");
printf(" --config <path> Path to configuration file\n");
printf(" --server Run in server mode\n");
printf(" --checksum Skip files based on checksum, not mod-time/size\n");
printf(" --compress-choice <alg> Compression algorithm (default: zstd)\n");
printf(" --compress-level <n> Compression level (default: 5)\n"); printf(" --compress-level <n> Compression level (default: 5)\n");
printf(" --temp-dir <dir> Temporary directory for files\n");
printf(" --compare-dest <dir> Compare destination\n");
printf(" --copy-dest <dir> Copy destination\n");
printf(" --link-dest <dir> Link destination\n");
printf(" --help Show this help\n"); printf(" --help Show this help\n");
printf(" -V, --version Show version\n"); printf(" -V, --version Show version\n");
} }
+35 -99
View File
@@ -45,59 +45,20 @@ static void config_set_defaults(Config* config) {
config->server_port = 8080; config->server_port = 8080;
config->timeout = 30; config->timeout = 30;
config->contimeout = 10; config->contimeout = 10;
config->quiet = false;
config->backup = false; config->backup = false;
config->backup_dir = NULL; config->backup_dir = NULL;
config->stats = false; config->stats = false;
config->max_depth = 0; config->max_depth = 0;
config->log_file = NULL; config->log_file = NULL;
config->queue_size = 100;
config->follow_symlinks = false; config->follow_symlinks = false;
config->partial = false; config->partial = false;
config->copy_links = false; config->copy_links = false;
config->safe_links = false; config->safe_links = false;
config->copy_unsafe_links = false; config->copy_unsafe_links = false;
config->preserve_hard_links = false;
config->preserve_acls = false;
config->preserve_xattrs = false;
config->preserve_devices = false;
config->preserve_sparse = false; config->preserve_sparse = false;
config->itemize_changes = false;
config->out_format = NULL;
config->info_level = 0;
config->debug_level = 0;
config->list_only = false;
config->human_readable = false;
config->update = false;
config->inplace = false; config->inplace = false;
config->append = false;
config->append_verify = false;
config->delete_excluded = false;
config->delete_after = false;
config->max_delete = 0;
config->filters = NULL;
config->files_from = NULL;
config->cvs_exclude = false;
config->prune_empty_dirs = false;
config->relative = false;
config->rsh_command = NULL;
config->rsync_path = NULL;
config->temp_dir = NULL;
config->compare_dest = NULL;
config->copy_dest = NULL;
config->link_dest = NULL;
config->partial_dir = NULL; config->partial_dir = NULL;
config->suffix = NULL; config->suffix = NULL;
config->delete_before = false;
config->address = NULL;
config->bind_address = NULL;
config->ipv6 = false;
config->ipv4 = false;
config->daemon = false;
config->daemon_config = NULL;
config->server_mode = false;
config->checksum = false;
config->compress_choice = NULL;
} }
Config* config_create(void) { Config* config_create(void) {
@@ -153,23 +114,8 @@ void config_delete(Config* config) {
free(config->tls_ca); free(config->tls_ca);
free(config->backup_dir); free(config->backup_dir);
free(config->server_host); free(config->server_host);
free(config->out_format);
free(config->files_from);
free(config->rsh_command);
free(config->rsync_path);
free(config->temp_dir);
free(config->compare_dest);
free(config->copy_dest);
free(config->link_dest);
free(config->partial_dir); free(config->partial_dir);
free(config->suffix); free(config->suffix);
free(config->address);
free(config->bind_address);
free(config->daemon_config);
free(config->compress_choice);
if (config->filters) {
array_list_delete(config->filters);
}
free(config); free(config);
} }
@@ -178,10 +124,11 @@ void config_delete(Config* config) {
* use_chunk_serialization, use_compression, use_metadata, compression_level, chunk_size, * use_chunk_serialization, use_compression, use_metadata, compression_level, chunk_size,
* use_sendfile, use_delete, use_incremental, use_delta, delta_block_size, delta_max_file_size, * use_sendfile, use_delete, use_incremental, use_delta, delta_block_size, delta_max_file_size,
* backup, backup_dir, follow_symlinks, copy_links, safe_links, copy_unsafe_links, * backup, backup_dir, follow_symlinks, copy_links, safe_links, copy_unsafe_links,
* preserve_hard_links, preserve_acls, preserve_xattrs, preserve_devices, preserve_sparse, * obsolete metadata flags, preserve_sparse, obsolete transfer flags, inplace, obsolete delete
* update, inplace, append, append_verify, delete_excluded, delete_after, max_delete, relative, * flags, obsolete path options, partial, partial_dir, suffix, obsolete checksum options, status
* prune_empty_dirs, temp_dir, partial, partial_dir, suffix, delete_before, checksum, *
* compress_choice, status * Obsolete fields remain as zero/empty compatibility slots. They must be consumed in this order
* until the protocol version is intentionally changed.
*/ */
bool config_send(int file_descriptor, const Config* config) { bool config_send(int file_descriptor, const Config* config) {
if (!send_str(file_descriptor, config->version)) if (!send_str(file_descriptor, config->version))
@@ -228,35 +175,36 @@ bool config_send(int file_descriptor, const Config* config) {
return false; return false;
if (!send_int(file_descriptor, config->copy_unsafe_links)) if (!send_int(file_descriptor, config->copy_unsafe_links))
return false; return false;
if (!send_int(file_descriptor, config->preserve_hard_links)) if (!send_int(file_descriptor, 0))
return false; return false;
if (!send_int(file_descriptor, config->preserve_acls)) if (!send_int(file_descriptor, 0))
return false; return false;
if (!send_int(file_descriptor, config->preserve_xattrs)) if (!send_int(file_descriptor, 0))
return false; return false;
if (!send_int(file_descriptor, config->preserve_devices)) if (!send_int(file_descriptor, 0))
return false; return false;
if (!send_int(file_descriptor, config->preserve_sparse)) if (!send_int(file_descriptor, config->preserve_sparse))
return false; return false;
if (!send_int(file_descriptor, config->update)) if (!send_int(file_descriptor, 0))
return false; return false;
if (!send_int(file_descriptor, config->inplace)) if (!send_int(file_descriptor, config->inplace))
return false; return false;
if (!send_int(file_descriptor, config->append)) if (!send_int(file_descriptor, 0))
return false; return false;
if (!send_int(file_descriptor, config->append_verify)) if (!send_int(file_descriptor, 0))
return false; return false;
if (!send_int(file_descriptor, config->delete_excluded)) if (!send_int(file_descriptor, 0))
return false; return false;
if (!send_int(file_descriptor, config->delete_after)) if (!send_int(file_descriptor, 0))
return false; return false;
if (!send_n_data(file_descriptor, &config->max_delete, sizeof(config->max_delete))) int obsolete_int = 0;
if (!send_n_data(file_descriptor, &obsolete_int, sizeof(obsolete_int)))
return false; return false;
if (!send_int(file_descriptor, config->relative)) if (!send_int(file_descriptor, 0))
return false; return false;
if (!send_int(file_descriptor, config->prune_empty_dirs)) if (!send_int(file_descriptor, 0))
return false; return false;
if (!send_str(file_descriptor, config->temp_dir ? config->temp_dir : "")) if (!send_str(file_descriptor, ""))
return false; return false;
if (!send_int(file_descriptor, config->partial)) if (!send_int(file_descriptor, config->partial))
return false; return false;
@@ -264,11 +212,11 @@ bool config_send(int file_descriptor, const Config* config) {
return false; return false;
if (!send_str(file_descriptor, config->suffix ? config->suffix : "")) if (!send_str(file_descriptor, config->suffix ? config->suffix : ""))
return false; return false;
if (!send_int(file_descriptor, config->delete_before)) if (!send_int(file_descriptor, 0))
return false; return false;
if (!send_int(file_descriptor, config->checksum)) if (!send_int(file_descriptor, 0))
return false; return false;
if (!send_str(file_descriptor, config->compress_choice ? config->compress_choice : "")) if (!send_str(file_descriptor, ""))
return false; return false;
Status status; Status status;
if (!receive_status(file_descriptor, &status)) if (!receive_status(file_descriptor, &status))
@@ -374,48 +322,39 @@ Config* config_receive(int file_descriptor) {
config->copy_unsafe_links = tmp; config->copy_unsafe_links = tmp;
if (!receive_int(file_descriptor, &tmp)) if (!receive_int(file_descriptor, &tmp))
goto error; goto error;
config->preserve_hard_links = tmp;
if (!receive_int(file_descriptor, &tmp)) if (!receive_int(file_descriptor, &tmp))
goto error; goto error;
config->preserve_acls = tmp;
if (!receive_int(file_descriptor, &tmp)) if (!receive_int(file_descriptor, &tmp))
goto error; goto error;
config->preserve_xattrs = tmp;
if (!receive_int(file_descriptor, &tmp)) if (!receive_int(file_descriptor, &tmp))
goto error; goto error;
config->preserve_devices = tmp;
if (!receive_int(file_descriptor, &tmp)) if (!receive_int(file_descriptor, &tmp))
goto error; goto error;
config->preserve_sparse = tmp; config->preserve_sparse = tmp;
if (!receive_int(file_descriptor, &tmp)) if (!receive_int(file_descriptor, &tmp))
goto error; goto error;
config->update = tmp;
if (!receive_int(file_descriptor, &tmp)) if (!receive_int(file_descriptor, &tmp))
goto error; goto error;
config->inplace = tmp; config->inplace = tmp;
if (!receive_int(file_descriptor, &tmp)) if (!receive_int(file_descriptor, &tmp))
goto error; goto error;
config->append = tmp;
if (!receive_int(file_descriptor, &tmp)) if (!receive_int(file_descriptor, &tmp))
goto error; goto error;
config->append_verify = tmp;
if (!receive_int(file_descriptor, &tmp))
goto error;
config->delete_excluded = tmp;
if (!receive_int(file_descriptor, &tmp))
goto error;
config->delete_after = tmp;
if (!receive_n_data(file_descriptor, &config->max_delete, sizeof(config->max_delete)))
goto error;
if (!receive_int(file_descriptor, &tmp)) if (!receive_int(file_descriptor, &tmp))
goto error; goto error;
config->relative = tmp;
if (!receive_int(file_descriptor, &tmp)) if (!receive_int(file_descriptor, &tmp))
goto error; goto error;
config->prune_empty_dirs = tmp; int obsolete_int = 0;
config->temp_dir = receive_str(file_descriptor); if (!receive_n_data(file_descriptor, &obsolete_int, sizeof(obsolete_int)))
if (config->temp_dir == NULL)
goto error; goto error;
if (!receive_int(file_descriptor, &tmp))
goto error;
if (!receive_int(file_descriptor, &tmp))
goto error;
char* obsolete_string = receive_str(file_descriptor);
if (obsolete_string == NULL)
goto error;
free(obsolete_string);
if (!receive_int(file_descriptor, &tmp)) if (!receive_int(file_descriptor, &tmp))
goto error; goto error;
config->partial = tmp; config->partial = tmp;
@@ -427,13 +366,12 @@ Config* config_receive(int file_descriptor) {
goto error; goto error;
if (!receive_int(file_descriptor, &tmp)) if (!receive_int(file_descriptor, &tmp))
goto error; goto error;
config->delete_before = tmp;
if (!receive_int(file_descriptor, &tmp)) if (!receive_int(file_descriptor, &tmp))
goto error; goto error;
config->checksum = tmp; obsolete_string = receive_str(file_descriptor);
config->compress_choice = receive_str(file_descriptor); if (obsolete_string == NULL)
if (config->compress_choice == NULL)
goto error; goto error;
free(obsolete_string);
if (!send_status(file_descriptor, STATUS_OK)) if (!send_status(file_descriptor, STATUS_OK))
goto error; goto error;
return config; return config;
@@ -444,10 +382,8 @@ error:
free(config->receive_root_directory); free(config->receive_root_directory);
free(config->server_host); free(config->server_host);
free(config->backup_dir); free(config->backup_dir);
free(config->temp_dir);
free(config->partial_dir); free(config->partial_dir);
free(config->suffix); free(config->suffix);
free(config->compress_choice);
free(config); free(config);
return NULL; return NULL;
} }
-59
View File
@@ -1,7 +1,6 @@
#ifndef CONFIG_H #ifndef CONFIG_H
#define CONFIG_H #define CONFIG_H
#include "array_list.h"
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
@@ -45,13 +44,11 @@ typedef struct Config {
char* tls_ca; char* tls_ca;
int timeout; int timeout;
int contimeout; int contimeout;
bool quiet;
bool backup; bool backup;
char* backup_dir; char* backup_dir;
bool stats; bool stats;
int max_depth; int max_depth;
FILE* log_file; FILE* log_file;
int queue_size;
bool follow_symlinks; bool follow_symlinks;
bool partial; bool partial;
@@ -60,46 +57,9 @@ typedef struct Config {
bool safe_links; bool safe_links;
bool copy_unsafe_links; bool copy_unsafe_links;
// Issue #121: Extended metadata preservation
bool preserve_hard_links;
bool preserve_acls;
bool preserve_xattrs;
bool preserve_devices;
bool preserve_sparse; bool preserve_sparse;
// Issue #122: Output/logging options
bool itemize_changes;
char* out_format;
int info_level;
int debug_level;
bool list_only;
bool human_readable;
// Issue #127: Transfer modes
bool update;
bool inplace; bool inplace;
bool append;
bool append_verify;
// Issue #128: Extended delete options
bool delete_excluded;
bool delete_after;
int max_delete;
// Issue #129: Advanced file selection
ArrayList* filters;
char* files_from;
bool cvs_exclude;
bool prune_empty_dirs;
bool relative;
// Issue #130: Remote shell/connection options
char* rsh_command;
char* rsync_path;
char* temp_dir;
char* compare_dest;
char* copy_dest;
char* link_dest;
// PR #174: Partial transfer resumption // PR #174: Partial transfer resumption
char* partial_dir; char* partial_dir;
@@ -107,25 +67,6 @@ typedef struct Config {
// PR #178: Backup versioning // PR #178: Backup versioning
char* suffix; char* suffix;
// PR #179: Delete policies
bool delete_before;
// PR #181: IPv6 and bind address
char* address;
char* bind_address;
bool ipv6;
bool ipv4;
// PR #182: Daemon/server mode
bool daemon;
char* daemon_config;
bool server_mode;
// PR #183: Checksum comparison
bool checksum;
// PR #184: Compression algorithm negotiation
char* compress_choice;
} Config; } Config;
/* This version must be bumped whenever config_send / config_receive wire format changes. */ /* This version must be bumped whenever config_send / config_receive wire format changes. */
+29
View File
@@ -207,6 +207,34 @@ static void test_parse_args_unknown_option() {
config_delete(cfg); config_delete(cfg);
} }
/* Parsed-but-unimplemented options must fail instead of being silently accepted. */
static void test_parse_args_rejects_unimplemented_options() {
static const char* const options[] = {
"-q", "--quiet", "--silent", "--queue-size",
"-H", "--hard-links", "-A", "--acls",
"-X", "--xattrs", "-D", "--devices",
"-i", "--itemize-changes", "--out-format", "--info",
"--debug", "--list-only", "-h", "--human-readable",
"-u", "--update", "--append", "--append-verify",
"--delete-excluded", "--delete-after", "--max-delete", "--filter",
"--files-from", "--cvs-exclude", "--prune-empty-dirs", "-R",
"--relative", "-e", "--rsh", "--rsync-path",
"--temp-dir", "--compare-dest", "--copy-dest", "--link-dest",
"--delete-before", "--address", "--bind-address", "--ipv6",
"--ipv4", "--daemon", "--config", "--server",
"--checksum", "--compress-choice"};
for (size_t i = 0; i < sizeof(options) / sizeof(options[0]); i++) {
Config* cfg = config_create();
char* argv[] = {"fastsync", (char*)options[i], "dummy", "/src", "/dst"};
int positional_args[2];
int positional_count = 0;
EXPECT_EQ_INT(parse_args(cfg, 5, argv, positional_args, &positional_count), -1);
config_delete(cfg);
}
}
/* Test parse_args with --archive flag */ /* Test parse_args with --archive flag */
static void test_parse_args_archive() { static void test_parse_args_archive() {
Config* cfg = config_create(); Config* cfg = config_create();
@@ -238,5 +266,6 @@ void test_client_cli() {
test_parse_args_invalid_compression_level(); test_parse_args_invalid_compression_level();
test_parse_args_valid_compression_level(); test_parse_args_valid_compression_level();
test_parse_args_unknown_option(); test_parse_args_unknown_option();
test_parse_args_rejects_unimplemented_options();
test_parse_args_archive(); test_parse_args_archive();
} }
+12 -12
View File
@@ -19,7 +19,7 @@ static void test_scanner_single_file() {
create_test_file(file1, content1); create_test_file(file1, content1);
DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 0, 0, DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 0, 0,
0, false, false, false, false, false); 0, false, false, false, false);
EXPECT_NOT_NULL(scanner); EXPECT_NOT_NULL(scanner);
Chunk* chunk = directory_scanner_next(scanner); Chunk* chunk = directory_scanner_next(scanner);
@@ -48,7 +48,7 @@ static void test_scanner_multiple_files() {
create_test_file(file2, content2); create_test_file(file2, content2);
DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 0, 0, DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 0, 0,
0, false, false, false, false, false); 0, false, false, false, false);
EXPECT_NOT_NULL(scanner); EXPECT_NOT_NULL(scanner);
const Chunk* chunk = directory_scanner_next(scanner); const Chunk* chunk = directory_scanner_next(scanner);
@@ -88,7 +88,7 @@ static void test_scanner_subdirectory() {
create_test_file(sub_file, content); create_test_file(sub_file, content);
DirectoryScanner* scanner = directory_scanner_create((char*)root, false, 0, NULL, 0, NULL, 0, 0, DirectoryScanner* scanner = directory_scanner_create((char*)root, false, 0, NULL, 0, NULL, 0, 0,
0, 0, false, false, false, false, false); 0, 0, false, false, false, false);
EXPECT_NOT_NULL(scanner); EXPECT_NOT_NULL(scanner);
int total_files = 0; int total_files = 0;
@@ -112,7 +112,7 @@ static void test_scanner_empty_directory() {
EXPECT_EQ_INT(mkdir(dir, 0755), 0); EXPECT_EQ_INT(mkdir(dir, 0755), 0);
DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 0, 0, DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 0, 0,
0, false, false, false, false, false); 0, false, false, false, false);
EXPECT_NOT_NULL(scanner); EXPECT_NOT_NULL(scanner);
const Chunk* chunk = directory_scanner_next(scanner); const Chunk* chunk = directory_scanner_next(scanner);
@@ -136,7 +136,7 @@ static void test_scanner_exclude_pattern() {
char* exclude[] = {"*.tmp"}; char* exclude[] = {"*.tmp"};
DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, exclude, 1, NULL, 0, 0, DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, exclude, 1, NULL, 0, 0,
0, 0, false, false, false, false, false); 0, 0, false, false, false, false);
EXPECT_NOT_NULL(scanner); EXPECT_NOT_NULL(scanner);
Chunk* chunk = directory_scanner_next(scanner); Chunk* chunk = directory_scanner_next(scanner);
@@ -169,7 +169,7 @@ static void test_scanner_exclude_subdirectory() {
char* exclude[] = {"*.tmp"}; char* exclude[] = {"*.tmp"};
DirectoryScanner* scanner = directory_scanner_create((char*)root, false, 0, exclude, 1, NULL, 0, DirectoryScanner* scanner = directory_scanner_create((char*)root, false, 0, exclude, 1, NULL, 0,
0, 0, 0, false, false, false, false, false); 0, 0, 0, false, false, false, false);
EXPECT_NOT_NULL(scanner); EXPECT_NOT_NULL(scanner);
int total = 0; int total = 0;
@@ -207,7 +207,7 @@ static void test_scanner_include_and_exclude() {
char* exclude[] = {"*.bak"}; char* exclude[] = {"*.bak"};
char* include[] = {"*.txt", "*.log"}; char* include[] = {"*.txt", "*.log"};
DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, exclude, 1, include, 2, DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, exclude, 1, include, 2,
0, 0, 0, false, false, false, false, false); 0, 0, 0, false, false, false, false);
EXPECT_NOT_NULL(scanner); EXPECT_NOT_NULL(scanner);
Chunk* chunk = directory_scanner_next(scanner); Chunk* chunk = directory_scanner_next(scanner);
@@ -244,7 +244,7 @@ static void test_scanner_max_size() {
/* max_size = 10 — only files <= 10 bytes */ /* max_size = 10 — only files <= 10 bytes */
DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 10, DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 10,
0, 0, false, false, false, false, false); 0, 0, false, false, false, false);
EXPECT_NOT_NULL(scanner); EXPECT_NOT_NULL(scanner);
Chunk* chunk = directory_scanner_next(scanner); Chunk* chunk = directory_scanner_next(scanner);
@@ -272,7 +272,7 @@ static void test_scanner_min_size() {
/* min_size = 1 — only files >= 1 byte */ /* min_size = 1 — only files >= 1 byte */
DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 0, 1, DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 0, 1,
0, false, false, false, false, false); 0, false, false, false, false);
EXPECT_NOT_NULL(scanner); EXPECT_NOT_NULL(scanner);
Chunk* chunk = directory_scanner_next(scanner); Chunk* chunk = directory_scanner_next(scanner);
@@ -302,7 +302,7 @@ static void test_scanner_size_range() {
/* Only files between 3 and 20 bytes */ /* Only files between 3 and 20 bytes */
DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 20, DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 20,
3, 0, false, false, false, false, false); 3, 0, false, false, false, false);
EXPECT_NOT_NULL(scanner); EXPECT_NOT_NULL(scanner);
Chunk* chunk = directory_scanner_next(scanner); Chunk* chunk = directory_scanner_next(scanner);
@@ -338,7 +338,7 @@ static void test_scanner_mixed_patterns() {
char* exclude[] = {"*.bak"}; char* exclude[] = {"*.bak"};
char* include[] = {"*.txt"}; char* include[] = {"*.txt"};
DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, exclude, 1, include, 1, DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, exclude, 1, include, 1,
10, 3, 0, false, false, false, false, false); 10, 3, 0, false, false, false, false);
EXPECT_NOT_NULL(scanner); EXPECT_NOT_NULL(scanner);
Chunk* chunk = directory_scanner_next(scanner); Chunk* chunk = directory_scanner_next(scanner);
@@ -369,7 +369,7 @@ static void test_scanner_no_patterns() {
create_test_file(f2, "second"); create_test_file(f2, "second");
DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 0, 0, DirectoryScanner* scanner = directory_scanner_create((char*)dir, false, 0, NULL, 0, NULL, 0, 0, 0,
0, false, false, false, false, false); 0, false, false, false, false);
EXPECT_NOT_NULL(scanner); EXPECT_NOT_NULL(scanner);
Chunk* chunk = directory_scanner_next(scanner); Chunk* chunk = directory_scanner_next(scanner);