Skip to content

Commit 53febd6

Browse files
committed
Fix protocol compatibility: Add feature negotiation for MSG_FLIST_COUNT to work with version <=3.4.1
- Add CF_SKIP_UNCHANGED compat flag (bit 9) - Add 'U' flag to client_info to advertise support - Only send MSG_FLIST_COUNT when both sides negotiated the feature - Only process MSG_FLIST_COUNT when negotiated - Prevents 'unexpected tag 11' error when mixing standard/custom rsync This fixes the crash when custom rsync (receiver) communicates with standard rsync (sender). The feature is now safely negotiated during protocol setup.
1 parent 616c84c commit 53febd6

File tree

4 files changed

+12
-2
lines changed

4 files changed

+12
-2
lines changed

compat.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ int proper_seed_order = 0;
8282
int inplace_partial = 0;
8383
int do_negotiated_strings = 0;
8484
int xmit_id0_names = 0;
85+
int skip_unchanged_negotiated = 0;
8586

8687
struct name_num_item *xattr_sum_nni;
8788
int xattr_sum_len = 0;
@@ -124,6 +125,7 @@ struct name_num_obj valid_compressions = {
124125
#define CF_INPLACE_PARTIAL_DIR (1<<6)
125126
#define CF_VARINT_FLIST_FLAGS (1<<7)
126127
#define CF_ID0_NAMES (1<<8)
128+
#define CF_SKIP_UNCHANGED (1<<9)
127129

128130
static const char *client_info;
129131

@@ -727,6 +729,8 @@ void setup_protocol(int f_out,int f_in)
727729
compat_flags |= CF_INPLACE_PARTIAL_DIR;
728730
if (strchr(client_info, 'u') != NULL)
729731
compat_flags |= CF_ID0_NAMES;
732+
if (strchr(client_info, 'U') != NULL)
733+
compat_flags |= CF_SKIP_UNCHANGED;
730734
if (strchr(client_info, 'v') != NULL) {
731735
do_negotiated_strings = 1;
732736
compat_flags |= CF_VARINT_FLIST_FLAGS;
@@ -748,6 +752,9 @@ void setup_protocol(int f_out,int f_in)
748752
proper_seed_order = compat_flags & CF_CHKSUM_SEED_FIX ? 1 : 0;
749753
xfer_flags_as_varint = compat_flags & CF_VARINT_FLIST_FLAGS ? 1 : 0;
750754
xmit_id0_names = compat_flags & CF_ID0_NAMES ? 1 : 0;
755+
if (compat_flags & CF_SKIP_UNCHANGED) {
756+
skip_unchanged_negotiated = 1;
757+
}
751758
if (!xfer_flags_as_varint && preserve_crtimes) {
752759
fprintf(stderr, "Both rsync versions must be at least 3.2.0 for --crtimes.\n");
753760
exit_cleanup(RERR_PROTOCOL);

generator.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ extern int am_sender;
3434
extern int am_daemon;
3535
extern int inc_recurse;
3636
extern int no_i_r_skip_unchanged;
37+
extern int skip_unchanged_negotiated;
3738
extern int relative_paths;
3839
extern struct stats stats;
3940
extern int implied_dirs;
@@ -2299,7 +2300,7 @@ static void prescan_for_unchanged(const char *local_name, int f_out)
22992300
skipped_count, active_count, (double)stats.total_size / 1024 / 1024 / 1024);
23002301

23012302
/* Send skipped count and adjusted total_size to sender for accurate progress display */
2302-
if (f_out >= 0) {
2303+
if (f_out >= 0 && skip_unchanged_negotiated) {
23032304
char buf[12];
23042305
SIVAL(buf, 0, skipped_count);
23052306
SIVAL64(buf, 4, stats.total_size);

io.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ extern int daemon_connection;
6060
extern int protocol_version;
6161
extern int remove_source_files;
6262
extern int preserve_hard_links;
63+
extern int skip_unchanged_negotiated;
6364
extern BOOL extra_flist_sending_enabled;
6465
extern BOOL flush_ok_after_signal;
6566
extern struct stats stats;
@@ -1512,7 +1513,7 @@ static void read_a_msg(void)
15121513
iobuf.in_multiplexed = 1;
15131514
break;
15141515
case MSG_FLIST_COUNT:
1515-
if (msg_bytes != 12 || !am_sender)
1516+
if (msg_bytes != 12 || !am_sender || !skip_unchanged_negotiated)
15161517
goto invalid_msg;
15171518
val = raw_read_int();
15181519
stats.num_skipped_files = val;

options.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3050,6 +3050,7 @@ int maybe_add_e_option(char *buf, int buf_len)
30503050
buf[x++] = 'I'; /* support inplace_partial behavior */
30513051
buf[x++] = 'v'; /* use varint for flist & compat flags; negotiate checksum */
30523052
buf[x++] = 'u'; /* include name of uid 0 & gid 0 in the id map */
3053+
buf[x++] = 'U'; /* support --no-i-r-skip-unchanged feature */
30533054

30543055
/* NOTE: Avoid using 'V' -- it was represented with the high bit of a write_byte() that became a write_varint(). */
30553056
}

0 commit comments

Comments
 (0)