Negotation env lists can specify "client & server"
This commit is contained in:
3
NEWS.md
3
NEWS.md
@@ -17,7 +17,8 @@ Protocol: 31 (unchanged)
|
||||
### ENHANCEMENTS:
|
||||
|
||||
- Allow the server side to restrict checksum & compression choices via
|
||||
the same environment variables the client uses.
|
||||
the same environment variables the client uses. Allow the env vars
|
||||
to be divided into "client list & server list" by the "`&`" char.
|
||||
|
||||
- Simplify how the negotiation environment variables apply to older rsync
|
||||
versions.
|
||||
|
||||
8
batch.c
8
batch.c
@@ -269,14 +269,6 @@ void write_batch_shell_file(void)
|
||||
err |= write_opt("--exclude-from", "-");
|
||||
}
|
||||
|
||||
/* We need to make sure that any protocol-based or negotiated choices get accurately
|
||||
* reflected in the options we save AND that we avoid any need for --read-batch to
|
||||
* do a string-based negotiation (since we don't write them into the file). */
|
||||
if (do_compression)
|
||||
err |= write_opt("--compress-choice", compress_choice);
|
||||
if (strchr(checksum_choice, ',') || xfersum_type != parse_csum_name(NULL, -1))
|
||||
err |= write_opt("--checksum-choice", checksum_choice);
|
||||
|
||||
/* Elide the filename args from the option list, but scan for them in reverse. */
|
||||
for (i = raw_argc-1, j = cooked_argc-1; i > 0 && j >= 0; i--) {
|
||||
if (strcmp(raw_argv[i], cooked_argv[j]) == 0) {
|
||||
|
||||
76
compat.c
76
compat.c
@@ -20,6 +20,7 @@
|
||||
*/
|
||||
|
||||
#include "rsync.h"
|
||||
#include "itypes.h"
|
||||
|
||||
extern int am_server;
|
||||
extern int am_sender;
|
||||
@@ -109,6 +110,9 @@ struct name_num_obj valid_compressions = {
|
||||
#define CF_INPLACE_PARTIAL_DIR (1<<6)
|
||||
#define CF_VARINT_FLIST_FLAGS (1<<7)
|
||||
|
||||
#define ENV_CHECKSUM 0
|
||||
#define ENV_COMPRESS 1
|
||||
|
||||
static const char *client_info;
|
||||
|
||||
/* The server makes sure that if either side only supports a pre-release
|
||||
@@ -262,10 +266,14 @@ static void init_nno_saw(struct name_num_obj *nno, int val)
|
||||
static int parse_nni_str(struct name_num_obj *nno, const char *from, char *tobuf, int tobuf_len)
|
||||
{
|
||||
char *to = tobuf, *tok = NULL;
|
||||
int cnt = 0;
|
||||
int saw_tok = 0, cnt = 0;
|
||||
|
||||
while (1) {
|
||||
if (*from == ' ' || !*from) {
|
||||
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]) {
|
||||
@@ -279,9 +287,10 @@ static int parse_nni_str(struct name_num_obj *nno, const char *from, char *tobuf
|
||||
}
|
||||
} else
|
||||
to = tok - (tok != tobuf);
|
||||
saw_tok = 1;
|
||||
tok = NULL;
|
||||
}
|
||||
if (!*from++)
|
||||
if (!ch)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
@@ -294,10 +303,13 @@ static int parse_nni_str(struct name_num_obj *nno, const char *from, char *tobuf
|
||||
to = tok - (tok != tobuf);
|
||||
break;
|
||||
}
|
||||
*to++ = *from++;
|
||||
*to++ = ch;
|
||||
}
|
||||
*to = '\0';
|
||||
|
||||
if (saw_tok && to == tobuf)
|
||||
return strlcpy(tobuf, "INVALID", MAX_NSTR_STRLEN);
|
||||
|
||||
return to - tobuf;
|
||||
}
|
||||
|
||||
@@ -349,14 +361,36 @@ static void recv_negotiate_str(int f_in, struct name_num_obj *nno, char *tmpbuf,
|
||||
exit_cleanup(RERR_UNSUPPORTED);
|
||||
}
|
||||
|
||||
static const char *getenv_nstr(int etype)
|
||||
{
|
||||
const char *env_str = getenv(etype == ENV_COMPRESS ? "RSYNC_COMPRESS_LIST" : "RSYNC_CHECKSUM_LIST");
|
||||
|
||||
/* When writing a batch file, we always negotiate an old-style choice. */
|
||||
if (write_batch)
|
||||
env_str = etype == ENV_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;
|
||||
}
|
||||
|
||||
/* If num2 < 0 then the caller is checking compress values, otherwise checksum values. */
|
||||
void validate_choice_vs_env(int num1, int num2)
|
||||
{
|
||||
struct name_num_obj *nno = num2 < 0 ? &valid_compressions : &valid_checksums;
|
||||
const char *list_str = getenv(num2 < 0 ? "RSYNC_COMPRESS_LIST" : "RSYNC_CHECKSUM_LIST");
|
||||
const char *list_str = getenv_nstr(num2 < 0 ? ENV_COMPRESS : ENV_CHECKSUM);
|
||||
char tmpbuf[MAX_NSTR_STRLEN];
|
||||
|
||||
if (!list_str || !*list_str)
|
||||
if (!list_str)
|
||||
return;
|
||||
|
||||
while (isSpace(list_str)) list_str++;
|
||||
|
||||
if (!*list_str)
|
||||
return;
|
||||
|
||||
init_nno_saw(nno, 0);
|
||||
@@ -422,17 +456,15 @@ int get_default_nno_list(struct name_num_obj *nno, char *to_buf, int to_buf_len,
|
||||
return len;
|
||||
}
|
||||
|
||||
static void send_negotiate_str(int f_out, struct name_num_obj *nno, const char *env_name)
|
||||
static void send_negotiate_str(int f_out, struct name_num_obj *nno, int etype)
|
||||
{
|
||||
char tmpbuf[MAX_NSTR_STRLEN];
|
||||
const char *list_str = getenv(env_name);
|
||||
const char *list_str = getenv_nstr(etype);
|
||||
int len;
|
||||
|
||||
if (list_str && *list_str) {
|
||||
init_nno_saw(nno, 0);
|
||||
len = parse_nni_str(nno, list_str, tmpbuf, MAX_NSTR_STRLEN);
|
||||
if (!len)
|
||||
len = strlcpy(tmpbuf, "FAIL", MAX_NSTR_STRLEN);
|
||||
list_str = tmpbuf;
|
||||
} else
|
||||
list_str = NULL;
|
||||
@@ -447,15 +479,10 @@ static void send_negotiate_str(int f_out, struct name_num_obj *nno, const char *
|
||||
rprintf(FINFO, "Client %s list (on client): %s\n", nno->type, tmpbuf);
|
||||
}
|
||||
|
||||
if (local_server) {
|
||||
/* A local server doesn't bother to send/recv the strings, it just constructs
|
||||
* and parses the same string on both sides. */
|
||||
recv_negotiate_str(-1, nno, tmpbuf, len);
|
||||
} else if (do_negotiated_strings) {
|
||||
/* 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. */
|
||||
/* 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)
|
||||
@@ -463,10 +490,10 @@ 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, "RSYNC_CHECKSUM_LIST");
|
||||
send_negotiate_str(f_out, &valid_checksums, ENV_CHECKSUM);
|
||||
|
||||
if (do_compression && !compress_choice)
|
||||
send_negotiate_str(f_out, &valid_compressions, "RSYNC_COMPRESS_LIST");
|
||||
send_negotiate_str(f_out, &valid_compressions, ENV_COMPRESS);
|
||||
|
||||
if (valid_checksums.saw) {
|
||||
char tmpbuf[MAX_NSTR_STRLEN];
|
||||
@@ -645,10 +672,8 @@ void setup_protocol(int f_out,int f_in)
|
||||
if (local_server || strchr(client_info, 'I') != NULL)
|
||||
compat_flags |= CF_INPLACE_PARTIAL_DIR;
|
||||
if (local_server || strchr(client_info, 'v') != NULL) {
|
||||
if (!write_batch || protocol_version >= 30) {
|
||||
do_negotiated_strings = 1;
|
||||
compat_flags |= CF_VARINT_FLIST_FLAGS;
|
||||
}
|
||||
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)
|
||||
@@ -697,6 +722,9 @@ void setup_protocol(int f_out,int f_in)
|
||||
#endif
|
||||
}
|
||||
|
||||
if (read_batch)
|
||||
do_negotiated_strings = 0;
|
||||
|
||||
if (need_unsorted_flist && (!am_sender || inc_recurse))
|
||||
unsort_ndx = ++file_extra_cnt;
|
||||
|
||||
|
||||
19
rsync.1.md
19
rsync.1.md
@@ -1506,7 +1506,10 @@ your home directory (remove the '=' for that).
|
||||
transfer checksum separately from the pre-transfer checksum, and it ignores
|
||||
"auto" and all unknown checksum names. If the remote rsync is not new
|
||||
enough to handle a checksum negotiation list, its list is assumed to
|
||||
consist of a single "md5" or "md4" item based on the protocol version.
|
||||
consist of a single "md5" or "md4" item based on the protocol version. If
|
||||
the environment variable contains a "`&`" character, the string is
|
||||
separated into the client list & server list, either one of which can be
|
||||
empty (giving that side the default list).
|
||||
|
||||
The use of the `--checksum-choice` option overrides this environment list.
|
||||
|
||||
@@ -2295,11 +2298,14 @@ your home directory (remove the '=' for that).
|
||||
|
||||
When both sides of the transfer are at least 3.2.0, rsync chooses the first
|
||||
algorithm in the client's list of choices that is also in the server's list
|
||||
of choices. Your default order can be customized by setting the environment
|
||||
of choices. The default order can be customized by setting the environment
|
||||
variable RSYNC_COMPRESS_LIST to a space-separated list of acceptable
|
||||
compression names. If no common compress choice is found, the client exits
|
||||
with an error. If the remote rsync is too old to support checksum negotiation,
|
||||
its list is assumed to be "zlib".
|
||||
with an error. If the remote rsync is too old to support checksum
|
||||
negotiation, its list is assumed to be "zlib". If the environment variable
|
||||
contains a "`&`" character, the string is separated into the client list &
|
||||
server list, either one of which can be empty (giving that side the default
|
||||
list).
|
||||
|
||||
There are some older rsync versions that were configured to reject a `-z`
|
||||
option and require the use of `-zz` because their compression library was
|
||||
@@ -3104,6 +3110,11 @@ your home directory (remove the '=' for that).
|
||||
with `--read-batch`. See the "BATCH MODE" section for details, and also
|
||||
the `--only-write-batch` option.
|
||||
|
||||
This option overrides the negotiated checksum & compress lists and always
|
||||
negotiates a choice based on old-school md5/md4/zlib choices. If you want
|
||||
a more modern choice, use the `--checksum-choice` (`--cc`) and/or
|
||||
`--compress-choice` (`--zc`) options.
|
||||
|
||||
0. `--only-write-batch=FILE`
|
||||
|
||||
Works like `--write-batch`, except that no updates are made on the
|
||||
|
||||
Reference in New Issue
Block a user