This patch adds backward-compatibility support for the --xattrs option.
Since the main release has never had xattr support, the trunk doesn't
need this code. If you want to make rsync 3.0.x communicate with an
older (patched) release, use this.
To use this patch, run these commands for a successful build:
patch -p1 <patches/acls.diff
patch -p1 <patches/xattrs.diff
./configure (optional if already run)
make
based-on: patch/master/acls
diff --git a/compat.c b/compat.c
--- a/compat.c
+++ b/compat.c
@@ -205,13 +205,6 @@ void setup_protocol(int f_out,int f_in)
if (protocol_version < 30) {
if (append_mode == 1)
append_mode = 2;
- if (preserve_xattrs && !local_server) {
- rprintf(FERROR,
- "--xattrs requires protocol 30 or higher"
- " (negotiated %d).\n",
- protocol_version);
- exit_cleanup(RERR_PROTOCOL);
- }
}
if (delete_mode && !(delete_before+delete_during+delete_after)) {
diff --git a/xattrs.c b/xattrs.c
--- a/xattrs.c
+++ b/xattrs.c
@@ -22,6 +22,7 @@
#include "rsync.h"
#include "ifuncs.h"
#include "inums.h"
+#include "io.h"
#include "lib/sysxattrs.h"
#ifdef SUPPORT_XATTRS
@@ -38,6 +39,7 @@ extern int preserve_devices;
extern int preserve_specials;
extern int checksum_seed;
extern int saw_xattr_filter;
+extern int protocol_version;
#define RSYNC_XAL_INITIAL 5
#define RSYNC_XAL_LIST_INITIAL 100
@@ -274,7 +276,7 @@ static int rsync_xal_get(const char *fname, item_list *xalp)
if (!(ptr = get_xattr_data(fname, name, &datum_len, 0)))
return -1;
- if (datum_len > MAX_FULL_DATUM) {
+ if (datum_len > MAX_FULL_DATUM && protocol_version >= 30) {
/* For large datums, we store a flag and a checksum. */
name_offset = 1 + MAX_DIGEST_LEN;
sum_init(-1, checksum_seed);
@@ -440,7 +442,7 @@ static int find_matching_xattr(const item_list *xalp)
|| rxas1[j].datum_len != rxas2[j].datum_len
|| strcmp(rxas1[j].name, rxas2[j].name))
break;
- if (rxas1[j].datum_len > MAX_FULL_DATUM) {
+ if (rxas1[j].datum_len > MAX_FULL_DATUM && protocol_version >= 30) {
if (memcmp(rxas1[j].datum + 1,
rxas2[j].datum + 1,
MAX_DIGEST_LEN) != 0)
@@ -515,13 +517,22 @@ int send_xattr(int f, stat_x *sxp)
{
int ndx = find_matching_xattr(sxp->xattr);
- /* Send 0 (-1 + 1) to indicate that literal xattr data follows. */
- write_varint(f, ndx + 1);
+ if (protocol_version < 30) {
+ if (ndx < 0)
+ write_byte(f, 'X');
+ else {
+ write_byte(f, 'x');
+ write_int(f, ndx);
+ }
+ } else {
+ /* Send 0 (-1 + 1) to indicate that literal xattr data follows. */
+ write_varint(f, ndx + 1);
+ }
if (ndx < 0) {
rsync_xa *rxa;
int count = sxp->xattr->count;
- write_varint(f, count);
+ write_varint30(f, count);
for (rxa = sxp->xattr->items; count--; rxa++) {
size_t name_len = rxa->name_len;
const char *name = rxa->name;
@@ -540,8 +551,8 @@ int send_xattr(int f, stat_x *sxp)
name_len += UPRE_LEN;
}
#endif
- write_varint(f, name_len);
- write_varint(f, rxa->datum_len);
+ write_varint30(f, name_len);
+ write_varint30(f, rxa->datum_len);
#ifndef HAVE_LINUX_XATTRS
if (name_len > rxa->name_len) {
write_buf(f, USER_PREFIX, UPRE_LEN);
@@ -549,7 +560,7 @@ int send_xattr(int f, stat_x *sxp)
}
#endif
write_buf(f, name, name_len);
- if (rxa->datum_len > MAX_FULL_DATUM)
+ if (rxa->datum_len > MAX_FULL_DATUM && protocol_version >= 30)
write_buf(f, rxa->datum + 1, MAX_DIGEST_LEN);
else
write_bigbuf(f, rxa->datum, rxa->datum_len);
@@ -600,7 +611,7 @@ int xattr_diff(struct file_struct *file, stat_x *sxp, int find_all)
cmp = rec_cnt ? strcmp(snd_rxa->name, rec_rxa->name) : -1;
if (cmp > 0)
same = 0;
- else if (snd_rxa->datum_len > MAX_FULL_DATUM) {
+ else if (snd_rxa->datum_len > MAX_FULL_DATUM && protocol_version >= 30) {
same = cmp == 0 && snd_rxa->datum_len == rec_rxa->datum_len
&& memcmp(snd_rxa->datum + 1, rec_rxa->datum + 1,
MAX_DIGEST_LEN) == 0;
@@ -646,6 +657,9 @@ void send_xattr_request(const char *fname, struct file_struct *file, int f_out)
int cnt, prior_req = 0;
rsync_xa *rxa;
+ if (protocol_version < 30)
+ return;
+
glst += F_XATTR(file);
lst = &glst->xa_items;
@@ -705,6 +719,9 @@ int recv_xattr_request(struct file_struct *file, int f_in)
rsync_xa *rxa;
int rel_pos, cnt, num, got_xattr_data = 0;
+ if (protocol_version < 30)
+ return 0;
+
if (F_XATTR(file) < 0) {
rprintf(FERROR, "recv_xattr_request: internal data error!\n");
exit_cleanup(RERR_PROTOCOL);
@@ -791,7 +808,22 @@ void receive_xattr(int f, struct file_struct *file)
#else
int need_sort = 1;
#endif
- int ndx = read_varint(f);
+ int ndx;
+
+ if (protocol_version >= 30)
+ ndx = read_varint(f);
+ else {
+ int tag = read_byte(f);
+ if (tag == 'x')
+ ndx = read_int(f) + 1;
+ else if (tag == 'X')
+ ndx = 0;
+ else {
+ rprintf(FERROR, "receive_xattr: unknown extended attribute"
+ " type tag (%02x) for %s\n", tag, f_name(file, NULL));
+ exit_cleanup(RERR_STREAMIO);
+ }
+ }
if (ndx < 0 || (size_t)ndx > rsync_xal_l.count) {
rprintf(FERROR, "receive_xattr: xa index %d out of"
@@ -804,7 +836,7 @@ void receive_xattr(int f, struct file_struct *file)
return;
}
- if ((count = read_varint(f)) != 0) {
+ if ((count = read_varint30(f)) != 0) {
(void)EXPAND_ITEM_LIST(&temp_xattr, rsync_xa, count);
temp_xattr.count = 0;
}
@@ -812,9 +844,10 @@ void receive_xattr(int f, struct file_struct *file)
for (num = 1; num <= count; num++) {
char *ptr, *name;
rsync_xa *rxa;
- size_t name_len = read_varint(f);
- size_t datum_len = read_varint(f);
- size_t dget_len = datum_len > MAX_FULL_DATUM ? 1 + MAX_DIGEST_LEN : datum_len;
+ size_t name_len = read_varint30(f);
+ size_t datum_len = read_varint30(f);
+ size_t dget_len = datum_len > MAX_FULL_DATUM && protocol_version >= 30
+ ? 1 + MAX_DIGEST_LEN : datum_len;
size_t extra_len = MIGHT_NEED_RPRE ? RPRE_LEN : 0;
if ((dget_len + extra_len < dget_len)
|| (dget_len + extra_len + name_len < dget_len + extra_len))