-+ if (x->count >= x->alloc) {
-+ size_t new_alloc;
-+ rsync_xa *new_rxas;
-+
-+ new_alloc = x->alloc < RSYNC_XAL_INITIAL ? RSYNC_XAL_INITIAL : x->alloc * 2;
-+ new_rxas = realloc_array(x->rxas, rsync_xa, new_alloc);
-+ if (!new_rxas)
-+ out_of_memory("rsync_xal_get");
-+ x->alloc = new_alloc;
-+ x->rxas = new_rxas;
-+ }
-+ datum_size = sys_lgetxattr(fname, name, datumbuf, datumbuf_len);
-+ if (datum_size > (ssize_t)datumbuf_len) {
-+ datum_size = -1;
-+ errno = ERANGE;
-+ }
-+ if (datum_size < 0) {
-+ if (errno == ENOTSUP)
-+ return -1;
-+ if (errno == ERANGE) {
-+ datum_size = sys_lgetxattr(fname, name, NULL, 0);
-+ if (datum_size < 0) {
-+ rprintf(FERROR,
-+ "%s: rsync_xal_get: lgetxattr %s failed: %s\n",
-+ fname, name, strerror(errno));
-+ return -1;
-+ }
-+ datumbuf = realloc_array(datumbuf, char, datum_size + 1);
-+ if (!datumbuf)
-+ out_of_memory("rsync_xal_get");
-+ datumbuf_len = datum_size;
-+ datum_size = sys_lgetxattr(fname, name, datumbuf, datumbuf_len);
-+ if (datum_size < 0) {
-+ rprintf(FERROR,
-+ "%s: rsync_xal_get: re-lgetxattr of %s failed: %s\n",
-+ name, fname, strerror(errno));
-+ return -1;
-+ }
-+ } else {
-+ rprintf(FERROR,
-+ "%s: rsync_xal_get: lgetxattr %s failed: %s\n",
-+ fname, name, strerror(errno));
-+ return -1;
-+ }
-+ }
-+ ptr = new_array(char, len + datum_size);
-+ if (!ptr)
-+ out_of_memory("rsync_xal_get");
-+ strcpy(ptr, name);
-+ if (datum_size)
-+ memcpy(ptr + len, datumbuf, datum_size);
-+ x->rxas[curr_rsync_xal.count].name_len = len;
-+ x->rxas[curr_rsync_xal.count].name = ptr;
-+ x->rxas[curr_rsync_xal.count].datum_len = datum_size;
-+ x->rxas[curr_rsync_xal.count].datum = ptr + len;
-+ x->count++;
-+ }
-+ if (x->count > 1) {
-+ qsort(x->rxas, x->count, sizeof (rsync_xa), rsync_xal_compare_names);
-+ }
-+ return 0;
-+}
-+
-+
-+/* generate the xattr(s) for this flist entry;
-+ * xattr(s) are either sent or cleaned-up by send_xattr() below */
-+
-+int make_xattr(const struct file_struct *file, const char *fname)
-+{
-+ if (!preserve_xattrs || !file)
-+ return 1;
-+
-+ rsync_xal_get(fname, &curr_rsync_xal);
-+ return 0; /* TODO: This needs to return 1 if no xattrs changed! */
-+}
-+
-+static ssize_t rsync_xal_find_matching(void)
-+{
-+ size_t i;
-+ size_t j;
-+
-+ for (i = 0; i < rsync_xal_l.count; i++) {
-+ /* Wrong number of elements? */
-+ if (rsync_xal_l.rxals[i].count != curr_rsync_xal.count)
-+ continue;
-+ /* any elements different? */
-+ for (j = 0; j < curr_rsync_xal.count; j++) {
-+ if (rsync_xal_l.rxals[i].rxas[j].name_len != curr_rsync_xal.rxas[j].name_len
-+ || rsync_xal_l.rxals[i].rxas[j].datum_len != curr_rsync_xal.rxas[j].datum_len
-+ || strcmp(rsync_xal_l.rxals[i].rxas[j].name, curr_rsync_xal.rxas[j].name)
-+ || memcmp(rsync_xal_l.rxals[i].rxas[j].datum, curr_rsync_xal.rxas[j].datum, curr_rsync_xal.rxas[j].datum_len))
-+ break;
-+ }
-+ /* no differences found. This is The One! */
-+ if (j == curr_rsync_xal.count)
-+ break;
-+ }
-+ if (i < rsync_xal_l.count)
-+ return i;
-+ return (ssize_t)-1;
-+}
-+
-+/* Store curr_rsync_xal on the end of rsync_xal_l */
-+static void rsync_xal_store(void)
-+{
-+ if (rsync_xal_l.count <= rsync_xal_l.alloc) {
-+ size_t new_alloc;
-+ void *new_xal;
-+
-+ new_alloc = rsync_xal_l.count < RSYNC_XAL_LIST_INITIAL ? RSYNC_XAL_LIST_INITIAL : rsync_xal_l.count * 2;
-+ new_xal = realloc_array(rsync_xal_l.rxals, rsync_xal, new_alloc);
-+ if (!new_xal)
-+ out_of_memory("rsync_xal_store");
-+ rsync_xal_l.alloc = new_alloc;
-+ rsync_xal_l.rxals = new_xal;
-+ }
-+ rsync_xal_l.rxals[rsync_xal_l.count] = curr_rsync_xal;
-+ rsync_xal_l.count++;
-+ curr_rsync_xal.count = 0;
-+ curr_rsync_xal.alloc = 0;
-+}
-+
-+/* send the make_xattr()-generated xattr list for this flist entry,
-+ * or clean up after an flist entry that's not being sent (f == -1) */
-+
-+void send_xattr(const struct file_struct *file, int f)
-+{
-+ ssize_t index;
-+
-+ if (!preserve_xattrs || !file)
-+ return;
-+
-+ if (f == -1) {
-+ rsync_xal_free(&curr_rsync_xal);
-+ return;
-+ }
-+ index = rsync_xal_find_matching();
-+ if (index != -1) {
-+ write_byte(f, 'x');
-+ write_int(f, index);
-+ rsync_xal_free(&curr_rsync_xal);
-+ } else {
-+ rsync_xa *rxa;
-+ size_t count;
-+
-+ count = curr_rsync_xal.count;
-+ write_byte(f, 'X');
-+ write_int(f, count);
-+ for (rxa = curr_rsync_xal.rxas; count--; rxa++) {
-+ write_int(f, rxa->name_len);
-+ write_int(f, rxa->datum_len);
-+ write_buf(f, rxa->name, rxa->name_len);
-+ write_buf(f, rxa->datum, rxa->datum_len);
-+ }
-+ rsync_xal_store();
-+ }
-+}
-+
-+
-+/* ------------------------------------------------------------------------- */
-+/* receive and build the rsync_xattr_lists */
-+
-+void receive_xattr(struct file_struct *file, int f)
-+{
-+ char *fname;
-+ int tag;
-+
-+ if (!preserve_xattrs)
-+ return;
-+ fname = f_name(file);
-+ tag = read_byte(f);
-+ if (tag != 'X' && tag != 'x') {
-+ rprintf(FERROR,
-+ "%s: receive_xattr: unknown extended attribute type tag: %c\n",
-+ fname, tag);
-+ exit_cleanup(RERR_STREAMIO);
-+ }
-+
-+ if (fxil.alloc <= fxil.count) {
-+ void *new_ptr;
-+ size_t new_alloc;
-+
-+ if (fxil.count < RSYNC_XAL_LIST_INITIAL)
-+ new_alloc = fxil.alloc + RSYNC_XAL_LIST_INITIAL;
-+ else
-+ new_alloc = fxil.alloc * 2;
-+ new_ptr = realloc_array(fxil.filexalidxs, file_xal_index, new_alloc);
-+ if (!new_ptr)
-+ out_of_memory("receive_xattr");
-+ if (verbose >= 3) {
-+ rprintf(FINFO, "receive_xattr to %lu bytes, %s move\n",
-+ (unsigned long)(new_alloc * sizeof (file_xal_index)),
-+ fxil.filexalidxs == new_ptr ? "did not" : "did");
-+ }
-+
-+ fxil.filexalidxs = new_ptr;
-+ fxil.alloc = new_alloc;
-+ }
-+
-+ fxil.filexalidxs[fxil.count].file = file;
-+ if (tag == 'X') {
-+ size_t count;
-+ size_t i;
-+
-+ fxil.filexalidxs[fxil.count].xalidx = rsync_xal_l.count;
-+
-+ count = read_int(f);
-+ curr_rsync_xal.count = count;
-+ curr_rsync_xal.alloc = count;
-+ curr_rsync_xal.rxas = new_array(rsync_xa, count);
-+ if (!curr_rsync_xal.rxas)
-+ out_of_memory("receive_xattr");
-+ for (i = 0; i < count; i++) {
-+ size_t name_len;
-+ size_t datum_len;
-+ char *ptr;
-+
-+ name_len = read_int(f);
-+ datum_len = read_int(f);
-+ ptr = new_array(char, name_len + datum_len);
-+ if (!ptr)
-+ out_of_memory("receive_xattr");
-+ read_buf(f, ptr, name_len);
-+ read_buf(f, ptr + name_len, datum_len);
-+ curr_rsync_xal.rxas[i].name_len = name_len;
-+ curr_rsync_xal.rxas[i].datum_len = datum_len;
-+ curr_rsync_xal.rxas[i].name = ptr;
-+ curr_rsync_xal.rxas[i].datum = ptr + name_len;
-+ }
-+ rsync_xal_store();
-+ } else {
-+ size_t index;
-+
-+ index = read_int(f);
-+ if (index >= rsync_xal_l.count) {
-+ rprintf(FERROR, "%s: receive_xattr: xa index %lu out of range\n",
-+ fname, (unsigned long)index);