CI / lint (pull_request) Successful in 20s
CI / sanitizers (undefined) (pull_request) Successful in 41s
CI / sanitizers (address) (pull_request) Successful in 41s
CI / fuzz-build (pull_request) Successful in 16s
CI / coverage (pull_request) Successful in 35s
CI / build-and-test (pull_request) Successful in 1m22s
CI / valgrind (pull_request) Successful in 36s
Address c-review nits on the itemize/output feature: - RSYNC_COMPAT.md: state that %b is the source length (always == %l) because no wire-byte counter exists; keep Summary equal to the matrix (recounted: 54 implemented / 84 not-implemented, 147 rows total - four rows flipped). - change_list.h/.c: document bytes_sent == size; note itemize/out-format lines never interleave with each other but may interleave with legacy log messages sharing the stream; mark the %M stat() path best-effort. - change_render_format scan in format_uses_mtime now mirrors the tokenizer (skips '%%' and unknown '%X' pairs) so a literal '%%M' no longer triggers the stat() fallback. - Integration tests: --list-only under -m; a changed file on a second --incremental run emits exactly one '>f' line while unchanged files print nothing; --log-file + --log-file-format under -m.
76 lines
3.4 KiB
C
76 lines
3.4 KiB
C
#ifndef CHANGE_LIST_H
|
|
#define CHANGE_LIST_H
|
|
|
|
#include "config.h"
|
|
#include "file_types.h"
|
|
#include <stdbool.h>
|
|
#include <sys/stat.h>
|
|
#include <time.h>
|
|
|
|
/*
|
|
* Shared per-file change-event / output model (rsync --itemize-changes,
|
|
* --out-format, --log-file-format, and --list-only all render from here).
|
|
*
|
|
* FastSync is a push-style tool: the client sends files from the source tree
|
|
* to a server that writes them under the destination root. Events are
|
|
* emitted by whichever code path decides a file's fate (the single-threaded
|
|
* send loop and the `-m` sender thread both call the same per-file sender), so
|
|
* all change events are emitted by exactly one thread and itemize/out-format
|
|
* lines never interleave with each other. They may still interleave with
|
|
* legacy log messages (log.c) that share the same stdout/log-file stream.
|
|
*/
|
|
|
|
typedef enum {
|
|
CHANGE_SENT, /* file data (full or delta) was transmitted */
|
|
CHANGE_UP_TO_DATE, /* receiver already had an identical file; skipped */
|
|
} ChangeDecision;
|
|
|
|
typedef struct {
|
|
const char* path; /* full source path */
|
|
ChangeDecision decision;
|
|
bool is_directory;
|
|
unsigned long long size; /* source file length in bytes */
|
|
/* The number of bytes reported for a sent file. FastSync has no wire-byte
|
|
* counter, so this is always the source length (== size / %l); actual
|
|
* post-compression/delta bytes on the wire are not counted. */
|
|
unsigned long long bytes_sent;
|
|
time_t mtime_sec; /* 0 when unknown */
|
|
} ChangeEvent;
|
|
|
|
/* True when any output mode is active and per-file events matter. */
|
|
bool change_list_enabled(const Config* config);
|
|
|
|
/* Render the rsync-style itemize line for a transferred file:
|
|
* `>f+++++++++ <path>`
|
|
* The 11-char code is `>f` (regular file transferred to the remote host)
|
|
* followed by c/s/t/p/o/g/u/a/x markers that are all `+` (value will be set
|
|
* / differs) because FastSync does not separately compare checksums, size,
|
|
* mtime, perms, owner, group, uid, acl, or xattr on the receiving side, so a
|
|
* sent file is reported as fully updated. Up-to-date files print no line
|
|
* (rsync single `-i` only shows changes). Caller frees the result. */
|
|
char* change_render_itemize(const ChangeEvent* event);
|
|
|
|
/* Expand an --out-format/--log-file-format template. Tokens:
|
|
* %f full source path %b "bytes sent" == the source length (%l);
|
|
* %n leaf (base) name actual post-compression/delta wire bytes
|
|
* %l file length in bytes are not counted
|
|
* %M mtime in whole seconds %% a literal percent sign
|
|
* Unknown %X sequences are preserved verbatim. Caller frees the result. */
|
|
char* change_render_format(const char* format, const ChangeEvent* event);
|
|
|
|
/* Render one --list-only long-listing entry:
|
|
* `-rw-r--r-- 12 2026/09/06 10:00:00 <path>`
|
|
* (ls -l style columns; mtime in the local time zone). Caller frees it. */
|
|
char* change_render_list_line(mode_t mode, unsigned long long size, time_t mtime, const char* path);
|
|
|
|
/* Emit an event to every active destination:
|
|
* stdout: --itemize-changes line, or the --out-format expansion when set;
|
|
* log file: the --log-file-format expansion (requires --log-file).
|
|
* CHANGE_UP_TO_DATE events produce no output. */
|
|
void change_emit(const Config* config, const ChangeEvent* event);
|
|
|
|
/* Build and emit a CHANGE_SENT event for a file the client just sent. */
|
|
void change_emit_file_sent(const Config* config, const File* file);
|
|
|
|
#endif
|