version 1.1, 2012/02/17 15:09:30
|
version 1.1.1.4, 2021/03/17 00:32:36
|
Line 3
|
Line 3
|
* |
* |
* Copyright (C) Andrew Tridgell 1996 |
* Copyright (C) Andrew Tridgell 1996 |
* Copyright (C) Paul Mackerras 1996 |
* Copyright (C) Paul Mackerras 1996 |
* Copyright (C) 2004-2009 Wayne Davison | * Copyright (C) 2004-2020 Wayne Davison |
* |
* |
* This program is free software; you can redistribute it and/or modify |
* This program is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* it under the terms of the GNU General Public License as published by |
Line 20
|
Line 20
|
*/ |
*/ |
|
|
#include "rsync.h" |
#include "rsync.h" |
|
#include "itypes.h" |
|
|
int remote_protocol = 0; |
|
int file_extra_cnt = 0; /* count of file-list extras that everyone gets */ |
|
int inc_recurse = 0; |
|
int compat_flags = 0; |
|
int use_safe_inc_flist = 0; |
|
|
|
extern int verbose; |
|
extern int am_server; |
extern int am_server; |
extern int am_sender; |
extern int am_sender; |
extern int local_server; |
extern int local_server; |
Line 35 extern int inplace;
|
Line 29 extern int inplace;
|
extern int recurse; |
extern int recurse; |
extern int use_qsort; |
extern int use_qsort; |
extern int allow_inc_recurse; |
extern int allow_inc_recurse; |
|
extern int preallocate_files; |
extern int append_mode; |
extern int append_mode; |
extern int fuzzy_basis; |
extern int fuzzy_basis; |
extern int read_batch; |
extern int read_batch; |
|
extern int write_batch; |
extern int delay_updates; |
extern int delay_updates; |
extern int checksum_seed; |
extern int checksum_seed; |
extern int basis_dir_cnt; |
extern int basis_dir_cnt; |
extern int prune_empty_dirs; |
extern int prune_empty_dirs; |
extern int protocol_version; |
extern int protocol_version; |
|
extern int detect_renamed; |
extern int protect_args; |
extern int protect_args; |
extern int preserve_uid; |
extern int preserve_uid; |
extern int preserve_gid; |
extern int preserve_gid; |
|
extern int preserve_atimes; |
|
extern int preserve_crtimes; |
extern int preserve_acls; |
extern int preserve_acls; |
extern int preserve_xattrs; |
extern int preserve_xattrs; |
|
extern int preserve_fileflags; |
|
extern int xfer_flags_as_varint; |
extern int need_messages_from_generator; |
extern int need_messages_from_generator; |
extern int delete_mode, delete_before, delete_during, delete_after; |
extern int delete_mode, delete_before, delete_during, delete_after; |
|
extern int do_compression; |
|
extern int do_compression_level; |
extern char *shell_cmd; |
extern char *shell_cmd; |
extern char *partial_dir; |
extern char *partial_dir; |
extern char *dest_option; |
|
extern char *files_from; |
extern char *files_from; |
extern char *filesfrom_host; |
extern char *filesfrom_host; |
extern struct filter_list_struct filter_list; | extern const char *checksum_choice; |
| extern const char *compress_choice; |
| extern filter_rule_list filter_list; |
extern int need_unsorted_flist; |
extern int need_unsorted_flist; |
#ifdef ICONV_OPTION |
#ifdef ICONV_OPTION |
extern iconv_t ic_send, ic_recv; |
extern iconv_t ic_send, ic_recv; |
extern char *iconv_opt; |
extern char *iconv_opt; |
#endif |
#endif |
|
extern struct name_num_obj valid_checksums; |
|
|
|
int remote_protocol = 0; |
|
int file_extra_cnt = 0; /* count of file-list extras that everyone gets */ |
|
int inc_recurse = 0; |
|
int compat_flags = 0; |
|
int use_safe_inc_flist = 0; |
|
int want_xattr_optim = 0; |
|
int proper_seed_order = 0; |
|
int inplace_partial = 0; |
|
int do_negotiated_strings = 0; |
|
int xmit_id0_names = 0; |
|
|
/* These index values are for the file-list's extra-attribute array. */ |
/* These index values are for the file-list's extra-attribute array. */ |
int uid_ndx, gid_ndx, acls_ndx, xattrs_ndx, unsort_ndx; | int pathname_ndx, depth_ndx, atimes_ndx, crtimes_ndx, uid_ndx, gid_ndx, fileflags_ndx, acls_ndx, xattrs_ndx, unsort_ndx; |
|
|
int receiver_symlink_times = 0; /* receiver can set the time on a symlink */ |
int receiver_symlink_times = 0; /* receiver can set the time on a symlink */ |
int sender_symlink_iconv = 0; /* sender should convert symlink content */ |
int sender_symlink_iconv = 0; /* sender should convert symlink content */ |
Line 72 int sender_symlink_iconv = 0; /* sender should convert
|
Line 88 int sender_symlink_iconv = 0; /* sender should convert
|
int filesfrom_convert = 0; |
int filesfrom_convert = 0; |
#endif |
#endif |
|
|
|
#define MAX_NSTR_STRLEN 256 |
|
|
|
struct name_num_obj valid_compressions = { |
|
"compress", NULL, NULL, 0, 0, { |
|
#ifdef SUPPORT_ZSTD |
|
{ CPRES_ZSTD, "zstd", NULL }, |
|
#endif |
|
#ifdef SUPPORT_LZ4 |
|
{ CPRES_LZ4, "lz4", NULL }, |
|
#endif |
|
{ CPRES_ZLIBX, "zlibx", NULL }, |
|
{ CPRES_ZLIB, "zlib", NULL }, |
|
{ CPRES_NONE, "none", NULL }, |
|
{ 0, NULL, NULL } |
|
} |
|
}; |
|
|
#define CF_INC_RECURSE (1<<0) |
#define CF_INC_RECURSE (1<<0) |
#define CF_SYMLINK_TIMES (1<<1) |
#define CF_SYMLINK_TIMES (1<<1) |
#define CF_SYMLINK_ICONV (1<<2) |
#define CF_SYMLINK_ICONV (1<<2) |
#define CF_SAFE_FLIST (1<<3) |
#define CF_SAFE_FLIST (1<<3) |
|
#define CF_AVOID_XATTR_OPTIM (1<<4) |
|
#define CF_CHKSUM_SEED_FIX (1<<5) |
|
#define CF_INPLACE_PARTIAL_DIR (1<<6) |
|
#define CF_VARINT_FLIST_FLAGS (1<<7) |
|
#define CF_ID0_NAMES (1<<8) |
|
|
static const char *client_info; |
static const char *client_info; |
|
|
Line 123 void set_allow_inc_recurse(void)
|
Line 161 void set_allow_inc_recurse(void)
|
allow_inc_recurse = 0; |
allow_inc_recurse = 0; |
else if (!am_sender |
else if (!am_sender |
&& (delete_before || delete_after |
&& (delete_before || delete_after |
|
|| detect_renamed |
|| delay_updates || prune_empty_dirs)) |
|| delay_updates || prune_empty_dirs)) |
allow_inc_recurse = 0; |
allow_inc_recurse = 0; |
else if (am_server && !local_server |
else if (am_server && !local_server |
Line 130 void set_allow_inc_recurse(void)
|
Line 169 void set_allow_inc_recurse(void)
|
allow_inc_recurse = 0; |
allow_inc_recurse = 0; |
} |
} |
|
|
|
void parse_compress_choice(int final_call) |
|
{ |
|
if (valid_compressions.negotiated_name) |
|
do_compression = valid_compressions.negotiated_num; |
|
else if (compress_choice) { |
|
struct name_num_item *nni = get_nni_by_name(&valid_compressions, compress_choice, -1); |
|
if (!nni) { |
|
rprintf(FERROR, "unknown compress name: %s\n", compress_choice); |
|
exit_cleanup(RERR_UNSUPPORTED); |
|
} |
|
do_compression = nni->num; |
|
if (am_server) |
|
validate_choice_vs_env(NSTR_COMPRESS, do_compression, -1); |
|
} else if (do_compression) |
|
do_compression = CPRES_ZLIB; |
|
else |
|
do_compression = CPRES_NONE; |
|
|
|
if (do_compression != CPRES_NONE && final_call) |
|
init_compression_level(); /* There's a chance this might turn compression off! */ |
|
|
|
if (do_compression == CPRES_NONE) |
|
compress_choice = NULL; |
|
|
|
/* Snag the compression name for both write_batch's option output & the following debug output. */ |
|
if (valid_compressions.negotiated_name) |
|
compress_choice = valid_compressions.negotiated_name; |
|
else if (compress_choice == NULL) { |
|
struct name_num_item *nni = get_nni_by_num(&valid_compressions, do_compression); |
|
compress_choice = nni ? nni->name : "UNKNOWN"; |
|
} |
|
|
|
if (final_call && DEBUG_GTE(NSTR, am_server ? 3 : 1) |
|
&& (do_compression != CPRES_NONE || do_compression_level != CLVL_NOT_SPECIFIED)) { |
|
rprintf(FINFO, "%s%s compress: %s (level %d)\n", |
|
am_server ? "Server" : "Client", |
|
valid_compressions.negotiated_name ? " negotiated" : "", |
|
compress_choice, do_compression_level); |
|
} |
|
} |
|
|
|
struct name_num_item *get_nni_by_name(struct name_num_obj *nno, const char *name, int len) |
|
{ |
|
struct name_num_item *nni; |
|
|
|
if (len < 0) |
|
len = strlen(name); |
|
|
|
for (nni = nno->list; nni->name; nni++) { |
|
if (strncasecmp(name, nni->name, len) == 0 && nni->name[len] == '\0') |
|
return nni; |
|
} |
|
|
|
return NULL; |
|
} |
|
|
|
struct name_num_item *get_nni_by_num(struct name_num_obj *nno, int num) |
|
{ |
|
struct name_num_item *nni; |
|
|
|
for (nni = nno->list; nni->name; nni++) { |
|
if (num == nni->num) |
|
return nni; |
|
} |
|
|
|
return NULL; |
|
} |
|
|
|
static void init_nno_saw(struct name_num_obj *nno, int val) |
|
{ |
|
struct name_num_item *nni; |
|
int cnt; |
|
|
|
if (!nno->saw_len) { |
|
for (nni = nno->list; nni->name; nni++) { |
|
if (nni->num >= nno->saw_len) |
|
nno->saw_len = nni->num + 1; |
|
} |
|
} |
|
|
|
if (!nno->saw) { |
|
nno->saw = new_array0(uchar, nno->saw_len); |
|
|
|
/* We'll take this opportunity to make sure that the main_name values are set right. */ |
|
for (cnt = 1, nni = nno->list; nni->name; nni++, cnt++) { |
|
if (nno->saw[nni->num]) |
|
nni->main_name = nno->list[nno->saw[nni->num]-1].name; |
|
else |
|
nno->saw[nni->num] = cnt; |
|
} |
|
} |
|
|
|
memset(nno->saw, val, nno->saw_len); |
|
} |
|
|
|
/* Simplify the user-provided string so that it contains valid names without any duplicates. |
|
* It also sets the "saw" flags to a 1-relative count of which name was seen first. */ |
|
static int parse_nni_str(struct name_num_obj *nno, const char *from, char *tobuf, int tobuf_len) |
|
{ |
|
char *to = tobuf, *tok = NULL; |
|
int saw_tok = 0, cnt = 0; |
|
|
|
while (1) { |
|
int at_space = isSpace(from); |
|
char ch = *from++; |
|
if (ch == '&') |
|
ch = '\0'; |
|
if (!ch || at_space) { |
|
if (tok) { |
|
struct name_num_item *nni = get_nni_by_name(nno, tok, to - tok); |
|
if (nni && !nno->saw[nni->num]) { |
|
nno->saw[nni->num] = ++cnt; |
|
if (nni->main_name) { |
|
to = tok + strlcpy(tok, nni->main_name, tobuf_len - (tok - tobuf)); |
|
if (to - tobuf >= tobuf_len) { |
|
to = tok - 1; |
|
break; |
|
} |
|
} |
|
} else |
|
to = tok - (tok != tobuf); |
|
saw_tok = 1; |
|
tok = NULL; |
|
} |
|
if (!ch) |
|
break; |
|
continue; |
|
} |
|
if (!tok) { |
|
if (to != tobuf) |
|
*to++ = ' '; |
|
tok = to; |
|
} |
|
if (to - tobuf >= tobuf_len - 1) { |
|
to = tok - (tok != tobuf); |
|
break; |
|
} |
|
*to++ = ch; |
|
} |
|
*to = '\0'; |
|
|
|
if (saw_tok && to == tobuf) |
|
return strlcpy(tobuf, "INVALID", MAX_NSTR_STRLEN); |
|
|
|
return to - tobuf; |
|
} |
|
|
|
/* This routine is always called with a tmpbuf of MAX_NSTR_STRLEN length, but the |
|
* buffer may be pre-populated with a "len" length string to use OR a len of -1 |
|
* to tell us to read a string from the fd. */ |
|
static void recv_negotiate_str(int f_in, struct name_num_obj *nno, char *tmpbuf, int len) |
|
{ |
|
struct name_num_item *ret = NULL; |
|
|
|
if (len < 0) |
|
len = read_vstring(f_in, tmpbuf, MAX_NSTR_STRLEN); |
|
|
|
if (DEBUG_GTE(NSTR, am_server ? 3 : 2)) { |
|
if (am_server) |
|
rprintf(FINFO, "Client %s list (on server): %s\n", nno->type, tmpbuf); |
|
else |
|
rprintf(FINFO, "Server %s list (on client): %s\n", nno->type, tmpbuf); |
|
} |
|
|
|
if (len > 0) { |
|
struct name_num_item *nni; |
|
int best = nno->saw_len; /* We want best == 1 from the client list, so start with a big number. */ |
|
char *space, *tok = tmpbuf; |
|
while (tok) { |
|
while (*tok == ' ') tok++; /* Should be unneeded... */ |
|
if (!*tok) |
|
break; |
|
if ((space = strchr(tok, ' ')) != NULL) |
|
*space = '\0'; |
|
nni = get_nni_by_name(nno, tok, -1); |
|
if (space) { |
|
*space = ' '; |
|
tok = space + 1; |
|
} else |
|
tok = NULL; |
|
if (!nni || !nno->saw[nni->num] || best <= nno->saw[nni->num]) |
|
continue; |
|
ret = nni; |
|
best = nno->saw[nni->num]; |
|
if (best == 1 || am_server) /* The server side stops at the first acceptable client choice */ |
|
break; |
|
} |
|
if (ret) { |
|
free(nno->saw); |
|
nno->saw = NULL; |
|
nno->negotiated_name = ret->main_name ? ret->main_name : ret->name; |
|
nno->negotiated_num = ret->num; |
|
return; |
|
} |
|
} |
|
|
|
if (!am_server || !do_negotiated_strings) { |
|
char *cp = tmpbuf; |
|
int j; |
|
rprintf(FERROR, "Failed to negotiate a %s choice.\n", nno->type); |
|
rprintf(FERROR, "%s list: %s\n", am_server ? "Client" : "Server", tmpbuf); |
|
/* Recreate our original list from the saw values. This can't overflow our huge |
|
* buffer because we don't have enough valid entries to get anywhere close. */ |
|
for (j = 1, *cp = '\0'; j <= nno->saw_len; j++) { |
|
struct name_num_item *nni; |
|
for (nni = nno->list; nni->name; nni++) { |
|
if (nno->saw[nni->num] == j) { |
|
*cp++ = ' '; |
|
cp += strlcpy(cp, nni->name, MAX_NSTR_STRLEN - (cp - tmpbuf)); |
|
break; |
|
} |
|
} |
|
} |
|
if (!*tmpbuf) |
|
strlcpy(cp, " INVALID", MAX_NSTR_STRLEN); |
|
rprintf(FERROR, "%s list:%s\n", am_server ? "Server" : "Client", tmpbuf); |
|
} |
|
|
|
exit_cleanup(RERR_UNSUPPORTED); |
|
} |
|
|
|
static const char *getenv_nstr(int ntype) |
|
{ |
|
const char *env_str = getenv(ntype == NSTR_COMPRESS ? "RSYNC_COMPRESS_LIST" : "RSYNC_CHECKSUM_LIST"); |
|
|
|
/* When writing a batch file, we always negotiate an old-style choice. */ |
|
if (write_batch) |
|
env_str = ntype == NSTR_COMPRESS ? "zlib" : protocol_version >= 30 ? "md5" : "md4"; |
|
|
|
if (am_server && env_str) { |
|
char *cp = strchr(env_str, '&'); |
|
if (cp) |
|
env_str = cp + 1; |
|
} |
|
|
|
return env_str; |
|
} |
|
|
|
void validate_choice_vs_env(int ntype, int num1, int num2) |
|
{ |
|
struct name_num_obj *nno = ntype == NSTR_COMPRESS ? &valid_compressions : &valid_checksums; |
|
const char *list_str = getenv_nstr(ntype); |
|
char tmpbuf[MAX_NSTR_STRLEN]; |
|
|
|
if (!list_str) |
|
return; |
|
|
|
while (isSpace(list_str)) list_str++; |
|
|
|
if (!*list_str) |
|
return; |
|
|
|
init_nno_saw(nno, 0); |
|
parse_nni_str(nno, list_str, tmpbuf, MAX_NSTR_STRLEN); |
|
|
|
if (ntype == NSTR_CHECKSUM) /* If "md4" is in the env list, all the old MD4 choices are OK too. */ |
|
nno->saw[CSUM_MD4_ARCHAIC] = nno->saw[CSUM_MD4_BUSTED] = nno->saw[CSUM_MD4_OLD] = nno->saw[CSUM_MD4]; |
|
|
|
if (!nno->saw[num1] || (num2 >= 0 && !nno->saw[num2])) { |
|
rprintf(FERROR, "Your --%s-choice value (%s) was refused by the server.\n", |
|
ntype == NSTR_COMPRESS ? "compress" : "checksum", |
|
ntype == NSTR_COMPRESS ? compress_choice : checksum_choice); |
|
exit_cleanup(RERR_UNSUPPORTED); |
|
} |
|
|
|
free(nno->saw); |
|
nno->saw = NULL; |
|
} |
|
|
|
/* The saw buffer is initialized and used to store ordinal values from 1 to N |
|
* for the order of the args in the array. If dup_markup == '\0', duplicates |
|
* are removed otherwise the char is prefixed to the duplicate term and, if it |
|
* is an opening paren/bracket/brace, the matching closing char is suffixed. |
|
* "none" is removed on the client side unless dup_markup != '\0'. */ |
|
int get_default_nno_list(struct name_num_obj *nno, char *to_buf, int to_buf_len, char dup_markup) |
|
{ |
|
struct name_num_item *nni; |
|
int len = 0, cnt = 0; |
|
char delim = '\0', post_delim; |
|
|
|
switch (dup_markup) { |
|
case '(': post_delim = ')'; break; |
|
case '[': post_delim = ']'; break; |
|
case '{': post_delim = '}'; break; |
|
default: post_delim = '\0'; break; |
|
} |
|
|
|
init_nno_saw(nno, 0); |
|
|
|
for (nni = nno->list, len = 0; nni->name; nni++) { |
|
if (nni->main_name) { |
|
if (!dup_markup) |
|
continue; |
|
delim = dup_markup; |
|
} |
|
if (nni->num == 0 && !am_server && !dup_markup) |
|
continue; |
|
if (len) |
|
to_buf[len++]= ' '; |
|
if (delim) { |
|
to_buf[len++]= delim; |
|
delim = post_delim; |
|
} |
|
len += strlcpy(to_buf+len, nni->name, to_buf_len - len); |
|
if (len >= to_buf_len - 3) |
|
exit_cleanup(RERR_UNSUPPORTED); /* IMPOSSIBLE... */ |
|
if (delim) { |
|
to_buf[len++]= delim; |
|
delim = '\0'; |
|
} |
|
nno->saw[nni->num] = ++cnt; |
|
} |
|
|
|
return len; |
|
} |
|
|
|
static void send_negotiate_str(int f_out, struct name_num_obj *nno, int ntype) |
|
{ |
|
char tmpbuf[MAX_NSTR_STRLEN]; |
|
const char *list_str = getenv_nstr(ntype); |
|
int len; |
|
|
|
if (list_str && *list_str) { |
|
init_nno_saw(nno, 0); |
|
len = parse_nni_str(nno, list_str, tmpbuf, MAX_NSTR_STRLEN); |
|
list_str = tmpbuf; |
|
} else |
|
list_str = NULL; |
|
|
|
if (!list_str || !*list_str) |
|
len = get_default_nno_list(nno, tmpbuf, MAX_NSTR_STRLEN, '\0'); |
|
|
|
if (DEBUG_GTE(NSTR, am_server ? 3 : 2)) { |
|
if (am_server) |
|
rprintf(FINFO, "Server %s list (on server): %s\n", nno->type, tmpbuf); |
|
else |
|
rprintf(FINFO, "Client %s list (on client): %s\n", nno->type, tmpbuf); |
|
} |
|
|
|
/* Each side sends their list of valid names to the other side and then both sides |
|
* pick the first name in the client's list that is also in the server's list. */ |
|
if (do_negotiated_strings) |
|
write_vstring(f_out, tmpbuf, len); |
|
} |
|
|
|
static void negotiate_the_strings(int f_in, int f_out) |
|
{ |
|
/* We send all the negotiation strings before we start to read them to help avoid a slow startup. */ |
|
|
|
if (!checksum_choice) |
|
send_negotiate_str(f_out, &valid_checksums, NSTR_CHECKSUM); |
|
|
|
if (do_compression && !compress_choice) |
|
send_negotiate_str(f_out, &valid_compressions, NSTR_COMPRESS); |
|
|
|
if (valid_checksums.saw) { |
|
char tmpbuf[MAX_NSTR_STRLEN]; |
|
int len; |
|
if (do_negotiated_strings) |
|
len = -1; |
|
else |
|
len = strlcpy(tmpbuf, protocol_version >= 30 ? "md5" : "md4", MAX_NSTR_STRLEN); |
|
recv_negotiate_str(f_in, &valid_checksums, tmpbuf, len); |
|
} |
|
|
|
if (valid_compressions.saw) { |
|
char tmpbuf[MAX_NSTR_STRLEN]; |
|
int len; |
|
if (do_negotiated_strings) |
|
len = -1; |
|
else |
|
len = strlcpy(tmpbuf, "zlib", MAX_NSTR_STRLEN); |
|
recv_negotiate_str(f_in, &valid_compressions, tmpbuf, len); |
|
} |
|
|
|
/* If the other side is too old to negotiate, the above steps just made sure that |
|
* the env didn't disallow the old algorithm. Mark things as non-negotiated. */ |
|
if (!do_negotiated_strings) |
|
valid_checksums.negotiated_name = valid_compressions.negotiated_name = NULL; |
|
} |
|
|
void setup_protocol(int f_out,int f_in) |
void setup_protocol(int f_out,int f_in) |
{ |
{ |
if (am_sender) | assert(file_extra_cnt == 0); |
file_extra_cnt += PTR_EXTRA_CNT; | assert(EXTRA64_CNT == 2 || EXTRA64_CNT == 1); |
| |
| /* All int64 values must be set first so that they are guaranteed to be |
| * aligned for direct int64-pointer memory access. */ |
| if (preserve_atimes) |
| atimes_ndx = (file_extra_cnt += EXTRA64_CNT); |
| if (preserve_crtimes) |
| crtimes_ndx = (file_extra_cnt += EXTRA64_CNT); |
| if (am_sender) /* This is most likely in the in64 union as well. */ |
| pathname_ndx = (file_extra_cnt += PTR_EXTRA_CNT); |
else |
else |
file_extra_cnt++; | depth_ndx = ++file_extra_cnt; |
if (preserve_uid) |
if (preserve_uid) |
uid_ndx = ++file_extra_cnt; |
uid_ndx = ++file_extra_cnt; |
if (preserve_gid) |
if (preserve_gid) |
gid_ndx = ++file_extra_cnt; |
gid_ndx = ++file_extra_cnt; |
|
if (preserve_fileflags || (force_change && !am_sender)) |
|
fileflags_ndx = ++file_extra_cnt; |
if (preserve_acls && !am_sender) |
if (preserve_acls && !am_sender) |
acls_ndx = ++file_extra_cnt; |
acls_ndx = ++file_extra_cnt; |
if (preserve_xattrs) |
if (preserve_xattrs) |
Line 163 void setup_protocol(int f_out,int f_in)
|
Line 594 void setup_protocol(int f_out,int f_in)
|
exit_cleanup(RERR_PROTOCOL); |
exit_cleanup(RERR_PROTOCOL); |
} |
} |
|
|
if (verbose > 3) { | if (DEBUG_GTE(PROTO, 1)) { |
rprintf(FINFO, "(%s) Protocol versions: remote=%d, negotiated=%d\n", |
rprintf(FINFO, "(%s) Protocol versions: remote=%d, negotiated=%d\n", |
am_server? "Server" : "Client", remote_protocol, protocol_version); |
am_server? "Server" : "Client", remote_protocol, protocol_version); |
} |
} |
Line 190 void setup_protocol(int f_out,int f_in)
|
Line 621 void setup_protocol(int f_out,int f_in)
|
if (read_batch) |
if (read_batch) |
check_batch_flags(); |
check_batch_flags(); |
|
|
|
#ifndef SUPPORT_PREALLOCATION |
|
if (preallocate_files && !am_sender) { |
|
rprintf(FERROR, "preallocation is not supported on this %s\n", |
|
am_server ? "Server" : "Client"); |
|
exit_cleanup(RERR_SYNTAX); |
|
} |
|
#endif |
|
|
if (protocol_version < 30) { |
if (protocol_version < 30) { |
if (append_mode == 1) |
if (append_mode == 1) |
append_mode = 2; |
append_mode = 2; |
if (preserve_acls && !local_server) { |
if (preserve_acls && !local_server) { |
rprintf(FERROR, |
rprintf(FERROR, |
"--acls requires protocol 30 or higher" | "--acls requires protocol 30 or higher" |
" (negotiated %d).\n", | " (negotiated %d).\n", |
protocol_version); | protocol_version); |
exit_cleanup(RERR_PROTOCOL); |
exit_cleanup(RERR_PROTOCOL); |
} |
} |
if (preserve_xattrs && !local_server) { |
if (preserve_xattrs && !local_server) { |
rprintf(FERROR, |
rprintf(FERROR, |
"--xattrs requires protocol 30 or higher" | "--xattrs requires protocol 30 or higher" |
" (negotiated %d).\n", | " (negotiated %d).\n", |
protocol_version); | protocol_version); |
exit_cleanup(RERR_PROTOCOL); |
exit_cleanup(RERR_PROTOCOL); |
} |
} |
} |
} |
Line 219 void setup_protocol(int f_out,int f_in)
|
Line 658 void setup_protocol(int f_out,int f_in)
|
if (protocol_version < 29) { |
if (protocol_version < 29) { |
if (fuzzy_basis) { |
if (fuzzy_basis) { |
rprintf(FERROR, |
rprintf(FERROR, |
"--fuzzy requires protocol 29 or higher" | "--fuzzy requires protocol 29 or higher" |
" (negotiated %d).\n", | " (negotiated %d).\n", |
protocol_version); | protocol_version); |
exit_cleanup(RERR_PROTOCOL); |
exit_cleanup(RERR_PROTOCOL); |
} |
} |
|
|
if (basis_dir_cnt && inplace) { |
if (basis_dir_cnt && inplace) { |
rprintf(FERROR, |
rprintf(FERROR, |
"%s with --inplace requires protocol 29 or higher" | "%s with --inplace requires protocol 29 or higher" |
" (negotiated %d).\n", | " (negotiated %d).\n", |
dest_option, protocol_version); | alt_dest_opt(0), protocol_version); |
exit_cleanup(RERR_PROTOCOL); |
exit_cleanup(RERR_PROTOCOL); |
} |
} |
|
|
if (basis_dir_cnt > 1) { |
if (basis_dir_cnt > 1) { |
rprintf(FERROR, |
rprintf(FERROR, |
"Using more than one %s option requires protocol" | "Using more than one %s option requires protocol" |
" 29 or higher (negotiated %d).\n", | " 29 or higher (negotiated %d).\n", |
dest_option, protocol_version); | alt_dest_opt(0), protocol_version); |
exit_cleanup(RERR_PROTOCOL); |
exit_cleanup(RERR_PROTOCOL); |
} |
} |
|
|
if (prune_empty_dirs) { |
if (prune_empty_dirs) { |
rprintf(FERROR, |
rprintf(FERROR, |
"--prune-empty-dirs requires protocol 29 or higher" | "--prune-empty-dirs requires protocol 29 or higher" |
" (negotiated %d).\n", | " (negotiated %d).\n", |
protocol_version); | protocol_version); |
exit_cleanup(RERR_PROTOCOL); |
exit_cleanup(RERR_PROTOCOL); |
} |
} |
} else if (protocol_version >= 30) { |
} else if (protocol_version >= 30) { |
Line 259 void setup_protocol(int f_out,int f_in)
|
Line 698 void setup_protocol(int f_out,int f_in)
|
#endif |
#endif |
if (local_server || strchr(client_info, 'f') != NULL) |
if (local_server || strchr(client_info, 'f') != NULL) |
compat_flags |= CF_SAFE_FLIST; |
compat_flags |= CF_SAFE_FLIST; |
write_byte(f_out, compat_flags); | if (local_server || strchr(client_info, 'x') != NULL) |
} else | compat_flags |= CF_AVOID_XATTR_OPTIM; |
compat_flags = read_byte(f_in); | if (local_server || strchr(client_info, 'C') != NULL) |
| compat_flags |= CF_CHKSUM_SEED_FIX; |
| if (local_server || strchr(client_info, 'I') != NULL) |
| compat_flags |= CF_INPLACE_PARTIAL_DIR; |
| if (local_server || strchr(client_info, 'u') != NULL) |
| compat_flags |= CF_ID0_NAMES; |
| if (local_server || strchr(client_info, 'v') != NULL) { |
| do_negotiated_strings = 1; |
| compat_flags |= CF_VARINT_FLIST_FLAGS; |
| } |
| if (strchr(client_info, 'V') != NULL) { /* Support a pre-release 'V' that got superseded */ |
| if (!write_batch) |
| compat_flags |= CF_VARINT_FLIST_FLAGS; |
| write_byte(f_out, compat_flags); |
| } else |
| write_varint(f_out, compat_flags); |
| } else { /* read_varint() is compatible with the older write_byte() when the 0x80 bit isn't on. */ |
| compat_flags = read_varint(f_in); |
| if (compat_flags & CF_VARINT_FLIST_FLAGS) |
| do_negotiated_strings = 1; |
| } |
/* The inc_recurse var MUST be set to 0 or 1. */ |
/* The inc_recurse var MUST be set to 0 or 1. */ |
inc_recurse = compat_flags & CF_INC_RECURSE ? 1 : 0; |
inc_recurse = compat_flags & CF_INC_RECURSE ? 1 : 0; |
|
want_xattr_optim = protocol_version >= 31 && !(compat_flags & CF_AVOID_XATTR_OPTIM); |
|
proper_seed_order = compat_flags & CF_CHKSUM_SEED_FIX ? 1 : 0; |
|
xfer_flags_as_varint = compat_flags & CF_VARINT_FLIST_FLAGS ? 1 : 0; |
|
xmit_id0_names = compat_flags & CF_ID0_NAMES ? 1 : 0; |
|
if (!xfer_flags_as_varint && preserve_crtimes) { |
|
fprintf(stderr, "Both rsync versions must be at least 3.2.0 for --crtimes.\n"); |
|
exit_cleanup(RERR_PROTOCOL); |
|
} |
|
if (!xfer_flags_as_varint && preserve_fileflags) { |
|
fprintf(stderr, "Both rsync versions must be at least 3.2.0 for --fileflags.\n"); |
|
exit_cleanup(RERR_PROTOCOL); |
|
} |
if (am_sender) { |
if (am_sender) { |
receiver_symlink_times = am_server |
receiver_symlink_times = am_server |
? strchr(client_info, 'L') != NULL |
? strchr(client_info, 'L') != NULL |
Line 281 void setup_protocol(int f_out,int f_in)
|
Line 752 void setup_protocol(int f_out,int f_in)
|
if (inc_recurse && !allow_inc_recurse) { |
if (inc_recurse && !allow_inc_recurse) { |
/* This should only be able to happen in a batch. */ |
/* This should only be able to happen in a batch. */ |
fprintf(stderr, |
fprintf(stderr, |
"Incompatible options specified for inc-recursive %s.\n", | "Incompatible options specified for inc-recursive %s.\n", |
read_batch ? "batch file" : "connection"); | read_batch ? "batch file" : "connection"); |
exit_cleanup(RERR_SYNTAX); |
exit_cleanup(RERR_SYNTAX); |
} |
} |
use_safe_inc_flist = !!(compat_flags & CF_SAFE_FLIST); | use_safe_inc_flist = (compat_flags & CF_SAFE_FLIST) || protocol_version >= 31; |
need_messages_from_generator = 1; |
need_messages_from_generator = 1; |
|
if (compat_flags & CF_INPLACE_PARTIAL_DIR) |
|
inplace_partial = 1; |
#ifdef CAN_SET_SYMLINK_TIMES |
#ifdef CAN_SET_SYMLINK_TIMES |
} else if (!am_sender) { |
} else if (!am_sender) { |
receiver_symlink_times = 1; |
receiver_symlink_times = 1; |
#endif |
#endif |
} |
} |
|
|
|
if (read_batch) |
|
do_negotiated_strings = 0; |
|
|
if (need_unsorted_flist && (!am_sender || inc_recurse)) |
if (need_unsorted_flist && (!am_sender || inc_recurse)) |
unsort_ndx = ++file_extra_cnt; |
unsort_ndx = ++file_extra_cnt; |
|
|
if (partial_dir && *partial_dir != '/' && (!am_server || local_server)) { |
if (partial_dir && *partial_dir != '/' && (!am_server || local_server)) { |
int flags = MATCHFLG_NO_PREFIXES | MATCHFLG_DIRECTORY; | int rflags = FILTRULE_NO_PREFIXES | FILTRULE_DIRECTORY; |
if (!am_sender || protocol_version >= 30) |
if (!am_sender || protocol_version >= 30) |
flags |= MATCHFLG_PERISHABLE; | rflags |= FILTRULE_PERISHABLE; |
parse_rule(&filter_list, partial_dir, flags, 0); | parse_filter_str(&filter_list, partial_dir, rule_template(rflags), 0); |
} |
} |
|
|
|
|
Line 313 void setup_protocol(int f_out,int f_in)
|
Line 789 void setup_protocol(int f_out,int f_in)
|
} |
} |
#endif |
#endif |
|
|
|
negotiate_the_strings(f_in, f_out); |
|
|
if (am_server) { |
if (am_server) { |
if (!checksum_seed) |
if (!checksum_seed) |
checksum_seed = time(NULL); | checksum_seed = time(NULL) ^ (getpid() << 6); |
write_int(f_out, checksum_seed); |
write_int(f_out, checksum_seed); |
} else { |
} else { |
checksum_seed = read_int(f_in); |
checksum_seed = read_int(f_in); |
} |
} |
|
|
|
parse_checksum_choice(1); /* Sets checksum_type & xfersum_type */ |
|
parse_compress_choice(1); /* Sets do_compression */ |
|
|
|
if (write_batch && !am_server) |
|
write_batch_shell_file(); |
|
|
|
init_flist(); |
} |
} |