|
version 1.1.1.1, 2012/02/17 15:09:30
|
version 1.1.1.4, 2021/03/17 00:32:36
|
|
Line 3
|
Line 3
|
| * Written by Jay Fenlason, vaguely based on the ACLs patch. |
* Written by Jay Fenlason, vaguely based on the ACLs patch. |
| * |
* |
| * Copyright (C) 2004 Red Hat, Inc. |
* Copyright (C) 2004 Red Hat, Inc. |
| * Copyright (C) 2006-2009 Wayne Davison | * Copyright (C) 2006-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 21
|
Line 21
|
| |
|
| #include "rsync.h" |
#include "rsync.h" |
| #include "ifuncs.h" |
#include "ifuncs.h" |
| |
#include "inums.h" |
| #include "lib/sysxattrs.h" |
#include "lib/sysxattrs.h" |
| |
|
| #ifdef SUPPORT_XATTRS |
#ifdef SUPPORT_XATTRS |
|
Line 32 extern int am_generator;
|
Line 33 extern int am_generator;
|
| extern int read_only; |
extern int read_only; |
| extern int list_only; |
extern int list_only; |
| extern int preserve_xattrs; |
extern int preserve_xattrs; |
| |
extern int preserve_hfs_compression; |
| extern int preserve_links; |
extern int preserve_links; |
| extern int preserve_devices; |
extern int preserve_devices; |
| extern int preserve_specials; |
extern int preserve_specials; |
| |
extern int checksum_type; |
| extern int checksum_seed; |
extern int checksum_seed; |
| |
extern int flist_csum_len; |
| |
extern int saw_xattr_filter; |
| |
|
| #define RSYNC_XAL_INITIAL 5 |
#define RSYNC_XAL_INITIAL 5 |
| #define RSYNC_XAL_LIST_INITIAL 100 |
#define RSYNC_XAL_LIST_INITIAL 100 |
| |
|
| |
#define GXD_NO_MISSING_ERROR (1<<0) |
| |
#define GXD_OMIT_COMPRESSED (1<<1) |
| |
#define GXD_FILE_IS_COMPRESSED (1<<2) |
| |
|
| #define MAX_FULL_DATUM 32 |
#define MAX_FULL_DATUM 32 |
| |
|
| #define HAS_PREFIX(str, prfx) (*(str) == *(prfx) \ | #define HAS_PREFIX(str, prfx) (*(str) == *(prfx) && strncmp(str, prfx, sizeof (prfx) - 1) == 0) |
| && strncmp(str, prfx, sizeof (prfx) - 1) == 0) | |
| |
|
| #define XATTR_ABBREV(x) ((size_t)((x).name - (x).datum) < (x).datum_len) |
#define XATTR_ABBREV(x) ((size_t)((x).name - (x).datum) < (x).datum_len) |
| |
|
|
Line 57 extern int checksum_seed;
|
Line 65 extern int checksum_seed;
|
| #define SPRE_LEN ((int)sizeof SYSTEM_PREFIX - 1) |
#define SPRE_LEN ((int)sizeof SYSTEM_PREFIX - 1) |
| |
|
| #ifdef HAVE_LINUX_XATTRS |
#ifdef HAVE_LINUX_XATTRS |
| #define MIGHT_NEED_RPRE (am_root < 0) | #define MIGHT_NEED_RPRE (am_root <= 0) |
| #define RSYNC_PREFIX USER_PREFIX "rsync." |
#define RSYNC_PREFIX USER_PREFIX "rsync." |
| #else |
#else |
| #define MIGHT_NEED_RPRE am_root |
#define MIGHT_NEED_RPRE am_root |
|
Line 71 extern int checksum_seed;
|
Line 79 extern int checksum_seed;
|
| #define XACC_ACL_ATTR RSYNC_PREFIX "%" XACC_ACL_SUFFIX |
#define XACC_ACL_ATTR RSYNC_PREFIX "%" XACC_ACL_SUFFIX |
| #define XDEF_ACL_SUFFIX "dacl" |
#define XDEF_ACL_SUFFIX "dacl" |
| #define XDEF_ACL_ATTR RSYNC_PREFIX "%" XDEF_ACL_SUFFIX |
#define XDEF_ACL_ATTR RSYNC_PREFIX "%" XDEF_ACL_SUFFIX |
| |
#define MD4_SUFFIX "md4" |
| |
#define MD4_ATTR RSYNC_PREFIX "%" MD4_SUFFIX |
| |
#define MD5_SUFFIX "md5" |
| |
#define MD5_ATTR RSYNC_PREFIX "%" MD5_SUFFIX |
| |
|
| |
#define APPLE_PREFIX "com.apple." |
| |
#define APLPRE_LEN ((int)sizeof APPLE_PREFIX - 1) |
| |
#define DECMPFS_SUFFIX "decmpfs" |
| |
#define RESOURCEFORK_SUFFIX "ResourceFork" |
| |
|
| |
#define UNREAD_DATA ((char *)1) |
| |
|
| |
#if MAX_DIGEST_LEN < SIZEOF_TIME_T |
| |
#error MAX_DIGEST_LEN is too small to hold an mtime |
| |
#endif |
| |
|
| typedef struct { |
typedef struct { |
| char *datum, *name; |
char *datum, *name; |
| size_t datum_len, name_len; |
size_t datum_len, name_len; |
| int num; |
int num; |
| } rsync_xa; |
} rsync_xa; |
| |
|
| |
struct _rsync_xa_list; |
| |
|
| |
typedef struct _rsync_xa_list_ref { |
| |
struct _rsync_xa_list_ref *next; |
| |
int ndx; |
| |
} rsync_xa_list_ref; |
| |
|
| |
typedef struct _rsync_xa_list { |
| |
int ndx; |
| |
int64 key; |
| |
item_list xa_items; |
| |
} rsync_xa_list; |
| |
|
| static size_t namebuf_len = 0; |
static size_t namebuf_len = 0; |
| static char *namebuf = NULL; |
static char *namebuf = NULL; |
| |
|
| static item_list empty_xattr = EMPTY_ITEM_LIST; | static const rsync_xa_list empty_xa_list = { |
| | .xa_items = EMPTY_ITEM_LIST, |
| | }; |
| | static const item_list empty_xattr = EMPTY_ITEM_LIST; |
| static item_list rsync_xal_l = EMPTY_ITEM_LIST; |
static item_list rsync_xal_l = EMPTY_ITEM_LIST; |
| |
static struct hashtable *rsync_xal_h = NULL; |
| |
|
| static size_t prior_xattr_count = (size_t)-1; |
static size_t prior_xattr_count = (size_t)-1; |
| |
|
|
Line 122 static int rsync_xal_compare_names(const void *x1, con
|
Line 162 static int rsync_xal_compare_names(const void *x1, con
|
| static ssize_t get_xattr_names(const char *fname) |
static ssize_t get_xattr_names(const char *fname) |
| { |
{ |
| ssize_t list_len; |
ssize_t list_len; |
| double arg; | int64 arg; |
| |
|
| if (!namebuf) { |
if (!namebuf) { |
| namebuf_len = 1024; |
namebuf_len = 1024; |
| namebuf = new_array(char, namebuf_len); |
namebuf = new_array(char, namebuf_len); |
| if (!namebuf) |
|
| out_of_memory("get_xattr_names"); |
|
| } |
} |
| |
|
| while (1) { |
while (1) { |
|
Line 140 static ssize_t get_xattr_names(const char *fname)
|
Line 178 static ssize_t get_xattr_names(const char *fname)
|
| } else if (errno == ENOTSUP) |
} else if (errno == ENOTSUP) |
| return 0; |
return 0; |
| else if (errno != ERANGE) { |
else if (errno != ERANGE) { |
| arg = (double)namebuf_len; | arg = namebuf_len; |
| got_error: |
got_error: |
| rsyserr(FERROR_XFER, errno, |
rsyserr(FERROR_XFER, errno, |
| "get_xattr_names: llistxattr(\"%s\",%.0f) failed", | "get_xattr_names: llistxattr(%s,%s) failed", |
| full_fname(fname), arg); | full_fname(fname), big_num(arg)); |
| return -1; |
return -1; |
| } |
} |
| list_len = sys_llistxattr(fname, NULL, 0); |
list_len = sys_llistxattr(fname, NULL, 0); |
|
Line 156 static ssize_t get_xattr_names(const char *fname)
|
Line 194 static ssize_t get_xattr_names(const char *fname)
|
| free(namebuf); |
free(namebuf); |
| namebuf_len = list_len + 1024; |
namebuf_len = list_len + 1024; |
| namebuf = new_array(char, namebuf_len); |
namebuf = new_array(char, namebuf_len); |
| if (!namebuf) |
|
| out_of_memory("get_xattr_names"); |
|
| } |
} |
| |
|
| return list_len; |
return list_len; |
|
Line 166 static ssize_t get_xattr_names(const char *fname)
|
Line 202 static ssize_t get_xattr_names(const char *fname)
|
| /* On entry, the *len_ptr parameter contains the size of the extra space we |
/* On entry, the *len_ptr parameter contains the size of the extra space we |
| * should allocate when we create a buffer for the data. On exit, it contains |
* should allocate when we create a buffer for the data. On exit, it contains |
| * the length of the datum. */ |
* the length of the datum. */ |
| static char *get_xattr_data(const char *fname, const char *name, size_t *len_ptr, | static char *get_xattr_data(const char *fname, const char *name, size_t *len_ptr, int flags) |
| int no_missing_error) | |
| { |
{ |
| size_t datum_len = sys_lgetxattr(fname, name, NULL, 0); |
size_t datum_len = sys_lgetxattr(fname, name, NULL, 0); |
| size_t extra_len = *len_ptr; |
size_t extra_len = *len_ptr; |
|
Line 176 static char *get_xattr_data(const char *fname, const c
|
Line 211 static char *get_xattr_data(const char *fname, const c
|
| *len_ptr = datum_len; |
*len_ptr = datum_len; |
| |
|
| if (datum_len == (size_t)-1) { |
if (datum_len == (size_t)-1) { |
| if (errno == ENOTSUP || no_missing_error) | if (errno == ENOTSUP || flags & GXD_NO_MISSING_ERROR) |
| return NULL; |
return NULL; |
| rsyserr(FERROR_XFER, errno, |
rsyserr(FERROR_XFER, errno, |
| "get_xattr_data: lgetxattr(\"%s\",\"%s\",0) failed", | "get_xattr_data: lgetxattr(%s,\"%s\",0) failed", |
| full_fname(fname), name); |
full_fname(fname), name); |
| return NULL; |
return NULL; |
| } |
} |
| |
|
| |
if (flags & GXD_OMIT_COMPRESSED && datum_len > MAX_FULL_DATUM |
| |
&& HAS_PREFIX(name, APPLE_PREFIX) |
| |
&& (strcmp(name+APLPRE_LEN, DECMPFS_SUFFIX) == 0 |
| |
|| (flags & GXD_FILE_IS_COMPRESSED && strcmp(name+APLPRE_LEN, RESOURCEFORK_SUFFIX) == 0))) { |
| |
/* If we are omitting compress-file-related data, we don't want to |
| |
* actually read this data. */ |
| |
return UNREAD_DATA; |
| |
} |
| |
|
| if (!datum_len && !extra_len) |
if (!datum_len && !extra_len) |
| extra_len = 1; /* request non-zero amount of memory */ |
extra_len = 1; /* request non-zero amount of memory */ |
| if (datum_len + extra_len < datum_len) | if (SIZE_MAX - datum_len < extra_len) |
| overflow_exit("get_xattr_data"); |
overflow_exit("get_xattr_data"); |
| if (!(ptr = new_array(char, datum_len + extra_len))) | ptr = new_array(char, datum_len + extra_len); |
| out_of_memory("get_xattr_data"); | |
| |
|
| if (datum_len) { |
if (datum_len) { |
| size_t len = sys_lgetxattr(fname, name, ptr, datum_len); |
size_t len = sys_lgetxattr(fname, name, ptr, datum_len); |
| if (len != datum_len) { |
if (len != datum_len) { |
| if (len == (size_t)-1) { |
if (len == (size_t)-1) { |
| rsyserr(FERROR_XFER, errno, |
rsyserr(FERROR_XFER, errno, |
| "get_xattr_data: lgetxattr(\"%s\",\"%s\",%ld)" | "get_xattr_data: lgetxattr(%s,\"%s\",%ld) failed", |
| " failed", full_fname(fname), name, (long)datum_len); | full_fname(fname), name, (long)datum_len); |
| } else { |
} else { |
| rprintf(FERROR_XFER, |
rprintf(FERROR_XFER, |
| "get_xattr_data: lgetxattr(\"%s\",\"%s\",%ld)" | "get_xattr_data: lgetxattr(%s,\"%s\",%ld) returned %ld\n", |
| " returned %ld\n", full_fname(fname), name, | full_fname(fname), name, |
| (long)datum_len, (long)len); | (long)datum_len, (long)len); |
| } |
} |
| free(ptr); |
free(ptr); |
| return NULL; |
return NULL; |
|
Line 212 static char *get_xattr_data(const char *fname, const c
|
Line 255 static char *get_xattr_data(const char *fname, const c
|
| return ptr; |
return ptr; |
| } |
} |
| |
|
| static int rsync_xal_get(const char *fname, item_list *xalp) | static void checksum_xattr_data(char *sum, const char *datum, size_t datum_len, stat_x *sxp) |
| { |
{ |
| |
if (datum == UNREAD_DATA) { |
| |
/* For abbreviated compressed data, we store the file's mtime as the checksum. */ |
| |
SIVAL(sum, 0, sxp->st.st_mtime); |
| |
#if SIZEOF_TIME_T > 4 |
| |
SIVAL(sum, 4, sxp->st.st_mtime >> 32); |
| |
#if MAX_DIGEST_LEN > 8 |
| |
memset(sum + 8, 0, MAX_DIGEST_LEN - 8); |
| |
#endif |
| |
#else |
| |
#if MAX_DIGEST_LEN > 4 |
| |
memset(sum + 4, 0, MAX_DIGEST_LEN - 4); |
| |
#endif |
| |
#endif |
| |
} else { |
| |
sum_init(-1, checksum_seed); |
| |
sum_update(datum, datum_len); |
| |
sum_end(sum); |
| |
} |
| |
} |
| |
|
| |
$$$ERROR$$$ the old patch needs reworking since rsync_xal_get() has totally changed! |
| |
|
| |
static int rsync_xal_get(const char *fname, stat_x *sxp) |
| |
{ |
| ssize_t list_len, name_len; |
ssize_t list_len, name_len; |
| size_t datum_len, name_offset; |
size_t datum_len, name_offset; |
| char *name, *ptr; |
char *name, *ptr; |
| #ifdef HAVE_LINUX_XATTRS |
#ifdef HAVE_LINUX_XATTRS |
| int user_only = am_sender ? 0 : am_root <= 0; | int user_only = am_sender ? 0 : !am_root; |
| #endif |
#endif |
| rsync_xa *rxa; |
rsync_xa *rxa; |
| int count; | int count, flags; |
| | item_list *xalp = sxp->xattr; |
| |
|
| /* This puts the name list into the "namebuf" buffer. */ |
/* This puts the name list into the "namebuf" buffer. */ |
| if ((list_len = get_xattr_names(fname)) < 0) |
if ((list_len = get_xattr_names(fname)) < 0) |
|
Line 231 static int rsync_xal_get(const char *fname, item_list
|
Line 299 static int rsync_xal_get(const char *fname, item_list
|
| name_len = strlen(name) + 1; |
name_len = strlen(name) + 1; |
| list_len -= name_len; |
list_len -= name_len; |
| |
|
| |
if (saw_xattr_filter) { |
| |
if (name_is_excluded(name, NAME_IS_XATTR, ALL_FILTERS)) |
| |
continue; |
| |
} |
| #ifdef HAVE_LINUX_XATTRS |
#ifdef HAVE_LINUX_XATTRS |
| /* We always ignore the system namespace, and non-root | /* Choose between ignoring the system namespace or (non-root) ignoring any non-user namespace. */ |
| * ignores everything but the user namespace. */ | else if (user_only ? !HAS_PREFIX(name, USER_PREFIX) : HAS_PREFIX(name, SYSTEM_PREFIX)) |
| if (user_only ? !HAS_PREFIX(name, USER_PREFIX) | |
| : HAS_PREFIX(name, SYSTEM_PREFIX)) | |
| continue; |
continue; |
| #endif |
#endif |
| |
|
| /* No rsync.%FOO attributes are copied w/o 2 -X options. */ |
/* No rsync.%FOO attributes are copied w/o 2 -X options. */ |
| if (name_len > RPRE_LEN && name[RPRE_LEN] == '%' | if (name_len > RPRE_LEN && name[RPRE_LEN] == '%' && HAS_PREFIX(name, RSYNC_PREFIX)) { |
| && HAS_PREFIX(name, RSYNC_PREFIX)) { | |
| if ((am_sender && preserve_xattrs < 2) |
if ((am_sender && preserve_xattrs < 2) |
| || (am_root < 0 |
|| (am_root < 0 |
| && (strcmp(name+RPRE_LEN+1, XSTAT_SUFFIX) == 0 |
&& (strcmp(name+RPRE_LEN+1, XSTAT_SUFFIX) == 0 |
| || strcmp(name+RPRE_LEN+1, XACC_ACL_SUFFIX) == 0 |
|| strcmp(name+RPRE_LEN+1, XACC_ACL_SUFFIX) == 0 |
| || strcmp(name+RPRE_LEN+1, XDEF_ACL_SUFFIX) == 0))) | || strcmp(name+RPRE_LEN+1, XDEF_ACL_SUFFIX) == 0 |
| | || strcmp(name+RPRE_LEN+1, MD4_SUFFIX) == 0 |
| | || strcmp(name+RPRE_LEN+1, MD5_SUFFIX) == 0))) |
| continue; |
continue; |
| } |
} |
| |
|
| datum_len = name_len; /* Pass extra size to get_xattr_data() */ |
datum_len = name_len; /* Pass extra size to get_xattr_data() */ |
| if (!(ptr = get_xattr_data(fname, name, &datum_len, 0))) | flags = GXD_OMIT_COMPRESSED; |
| | if (preserve_hfs_compression && sxp->st.st_flags & UF_COMPRESSED) |
| | flags |= GXD_FILE_IS_COMPRESSED; |
| | if (!(ptr = get_xattr_data(fname, name, &datum_len, flags))) |
| return -1; |
return -1; |
| |
|
| if (datum_len > MAX_FULL_DATUM) { |
if (datum_len > MAX_FULL_DATUM) { |
| /* For large datums, we store a flag and a checksum. */ |
/* For large datums, we store a flag and a checksum. */ |
| |
char *datum = ptr; |
| name_offset = 1 + MAX_DIGEST_LEN; |
name_offset = 1 + MAX_DIGEST_LEN; |
| sum_init(checksum_seed); | sum_init(-1, checksum_seed); |
| sum_update(ptr, datum_len); |
sum_update(ptr, datum_len); |
| free(ptr); |
free(ptr); |
| |
|
| if (!(ptr = new_array(char, name_offset + name_len))) | ptr = new_array(char, name_offset + name_len); |
| out_of_memory("rsync_xal_get"); | |
| *ptr = XSTATE_ABBREV; |
*ptr = XSTATE_ABBREV; |
| sum_end(ptr + 1); | checksum_xattr_data(ptr+1, datum, datum_len, sxp); |
| | if (datum != UNREAD_DATA) |
| | free(datum); |
| } else |
} else |
| name_offset = datum_len; |
name_offset = datum_len; |
| |
|
|
Line 307 int get_xattr(const char *fname, stat_x *sxp)
|
Line 383 int get_xattr(const char *fname, stat_x *sxp)
|
| if (!preserve_devices) |
if (!preserve_devices) |
| #endif |
#endif |
| return 0; |
return 0; |
| } | } else if (IS_MISSING_FILE(sxp->st)) |
| | return 0; |
| |
|
| if (rsync_xal_get(fname, sxp->xattr) < 0) { | if (rsync_xal_get(fname, sxp) < 0) { |
| free_xattr(sxp); |
free_xattr(sxp); |
| return -1; |
return -1; |
| } |
} |
|
Line 322 int copy_xattrs(const char *source, const char *dest)
|
Line 399 int copy_xattrs(const char *source, const char *dest)
|
| size_t datum_len; |
size_t datum_len; |
| char *name, *ptr; |
char *name, *ptr; |
| #ifdef HAVE_LINUX_XATTRS |
#ifdef HAVE_LINUX_XATTRS |
| int user_only = am_root <= 0; | int user_only = am_sender ? 0 : am_root <= 0; |
| #endif |
#endif |
| |
|
| /* This puts the name list into the "namebuf" buffer. */ |
/* This puts the name list into the "namebuf" buffer. */ |
|
Line 333 int copy_xattrs(const char *source, const char *dest)
|
Line 410 int copy_xattrs(const char *source, const char *dest)
|
| name_len = strlen(name) + 1; |
name_len = strlen(name) + 1; |
| list_len -= name_len; |
list_len -= name_len; |
| |
|
| |
if (saw_xattr_filter) { |
| |
if (name_is_excluded(name, NAME_IS_XATTR, ALL_FILTERS)) |
| |
continue; |
| |
} |
| #ifdef HAVE_LINUX_XATTRS |
#ifdef HAVE_LINUX_XATTRS |
| /* We always ignore the system namespace, and non-root | /* Choose between ignoring the system namespace or (non-root) ignoring any non-user namespace. */ |
| * ignores everything but the user namespace. */ | else if (user_only ? !HAS_PREFIX(name, USER_PREFIX) : HAS_PREFIX(name, SYSTEM_PREFIX)) |
| if (user_only ? !HAS_PREFIX(name, USER_PREFIX) | |
| : HAS_PREFIX(name, SYSTEM_PREFIX)) | |
| continue; |
continue; |
| #endif |
#endif |
| |
|
| datum_len = 0; |
datum_len = 0; |
| if (!(ptr = get_xattr_data(source, name, &datum_len, 0))) |
if (!(ptr = get_xattr_data(source, name, &datum_len, 0))) |
| return -1; |
return -1; |
| |
if (ptr == UNREAD_DATA) |
| |
continue; /* XXX Is this right? */ |
| if (sys_lsetxattr(dest, name, ptr, datum_len) < 0) { |
if (sys_lsetxattr(dest, name, ptr, datum_len) < 0) { |
| int save_errno = errno ? errno : EINVAL; |
int save_errno = errno ? errno : EINVAL; |
| rsyserr(FERROR_XFER, errno, |
rsyserr(FERROR_XFER, errno, |
| "copy_xattrs: lsetxattr(\"%s\",\"%s\") failed", | "copy_xattrs: lsetxattr(%s,\"%s\") failed", |
| full_fname(dest), name); |
full_fname(dest), name); |
| errno = save_errno; |
errno = save_errno; |
| return -1; |
return -1; |
|
Line 358 int copy_xattrs(const char *source, const char *dest)
|
Line 439 int copy_xattrs(const char *source, const char *dest)
|
| return 0; |
return 0; |
| } |
} |
| |
|
| static int find_matching_xattr(item_list *xalp) | static int64 xattr_lookup_hash(const item_list *xalp) |
| { |
{ |
| size_t i, j; | const rsync_xa *rxas = xalp->items; |
| item_list *lst = rsync_xal_l.items; | size_t i; |
| | int64 key = hashlittle(&xalp->count, sizeof xalp->count); |
| |
|
| for (i = 0; i < rsync_xal_l.count; i++) { | for (i = 0; i < xalp->count; i++) { |
| rsync_xa *rxas1 = lst[i].items; | key += hashlittle(rxas[i].name, rxas[i].name_len); |
| rsync_xa *rxas2 = xalp->items; | if (rxas[i].datum_len > MAX_FULL_DATUM) |
| | key += hashlittle(rxas[i].datum, MAX_DIGEST_LEN); |
| | else |
| | key += hashlittle(rxas[i].datum, rxas[i].datum_len); |
| | } |
| |
|
| |
if (key == 0) { |
| |
/* This is very unlikely, but we should never |
| |
* return 0 as hashtable_find() doesn't like it. */ |
| |
return 1; |
| |
} |
| |
|
| |
return key; |
| |
} |
| |
|
| |
static int find_matching_xattr(const item_list *xalp) |
| |
{ |
| |
const struct ht_int64_node *node; |
| |
const rsync_xa_list_ref *ref; |
| |
int64 key; |
| |
|
| |
if (rsync_xal_h == NULL) |
| |
return -1; |
| |
|
| |
key = xattr_lookup_hash(xalp); |
| |
|
| |
node = hashtable_find(rsync_xal_h, key, NULL); |
| |
if (node == NULL) |
| |
return -1; |
| |
|
| |
if (node->data == NULL) |
| |
return -1; |
| |
|
| |
for (ref = node->data; ref != NULL; ref = ref->next) { |
| |
const rsync_xa_list *ptr = rsync_xal_l.items; |
| |
const rsync_xa *rxas1; |
| |
const rsync_xa *rxas2 = xalp->items; |
| |
size_t j; |
| |
|
| |
ptr += ref->ndx; |
| |
rxas1 = ptr->xa_items.items; |
| |
|
| /* Wrong number of elements? */ |
/* Wrong number of elements? */ |
| if (lst[i].count != xalp->count) | if (ptr->xa_items.count != xalp->count) |
| continue; |
continue; |
| /* any elements different? */ |
/* any elements different? */ |
| for (j = 0; j < xalp->count; j++) { |
for (j = 0; j < xalp->count; j++) { |
|
Line 389 static int find_matching_xattr(item_list *xalp)
|
Line 511 static int find_matching_xattr(item_list *xalp)
|
| } |
} |
| /* no differences found. This is The One! */ |
/* no differences found. This is The One! */ |
| if (j == xalp->count) |
if (j == xalp->count) |
| return i; | return ref->ndx; |
| } |
} |
| |
|
| return -1; |
return -1; |
| |
#endif |
| } |
} |
| |
|
| /* Store *xalp on the end of rsync_xal_l */ |
/* Store *xalp on the end of rsync_xal_l */ |
| static void rsync_xal_store(item_list *xalp) | static int rsync_xal_store(item_list *xalp) |
| { |
{ |
| item_list *new_lst = EXPAND_ITEM_LIST(&rsync_xal_l, item_list, RSYNC_XAL_LIST_INITIAL); | struct ht_int64_node *node; |
| | int ndx = rsync_xal_l.count; /* pre-incremented count */ |
| | rsync_xa_list *new_list = EXPAND_ITEM_LIST(&rsync_xal_l, rsync_xa_list, RSYNC_XAL_LIST_INITIAL); |
| | rsync_xa_list_ref *new_ref; |
| /* Since the following call starts a new list, we know it will hold the |
/* Since the following call starts a new list, we know it will hold the |
| * entire initial-count, not just enough space for one new item. */ |
* entire initial-count, not just enough space for one new item. */ |
| *new_lst = empty_xattr; | *new_list = empty_xa_list; |
| (void)EXPAND_ITEM_LIST(new_lst, rsync_xa, xalp->count); | (void)EXPAND_ITEM_LIST(&new_list->xa_items, rsync_xa, xalp->count); |
| memcpy(new_lst->items, xalp->items, xalp->count * sizeof (rsync_xa)); | memcpy(new_list->xa_items.items, xalp->items, xalp->count * sizeof (rsync_xa)); |
| new_lst->count = xalp->count; | new_list->xa_items.count = xalp->count; |
| xalp->count = 0; |
xalp->count = 0; |
| |
|
| |
new_list->ndx = ndx; |
| |
new_list->key = xattr_lookup_hash(&new_list->xa_items); |
| |
|
| |
if (rsync_xal_h == NULL) |
| |
rsync_xal_h = hashtable_create(512, HT_KEY64); |
| |
if (rsync_xal_h == NULL) |
| |
out_of_memory("rsync_xal_h hashtable_create()"); |
| |
|
| |
new_ref = new0(rsync_xa_list_ref); |
| |
new_ref->ndx = ndx; |
| |
|
| |
node = hashtable_find(rsync_xal_h, new_list->key, new_ref); |
| |
if (node->data != (void*)new_ref) { |
| |
rsync_xa_list_ref *ref = node->data; |
| |
|
| |
while (ref != NULL) { |
| |
if (ref->next != NULL) { |
| |
ref = ref->next; |
| |
continue; |
| |
} |
| |
|
| |
ref->next = new_ref; |
| |
break; |
| |
} |
| |
} |
| |
|
| |
return ndx; |
| } |
} |
| |
|
| /* Send the make_xattr()-generated xattr list for this flist entry. */ |
/* Send the make_xattr()-generated xattr list for this flist entry. */ |
|
Line 450 int send_xattr(int f, stat_x *sxp)
|
Line 604 int send_xattr(int f, stat_x *sxp)
|
| if (rxa->datum_len > MAX_FULL_DATUM) |
if (rxa->datum_len > MAX_FULL_DATUM) |
| write_buf(f, rxa->datum + 1, MAX_DIGEST_LEN); |
write_buf(f, rxa->datum + 1, MAX_DIGEST_LEN); |
| else |
else |
| write_buf(f, rxa->datum, rxa->datum_len); | write_bigbuf(f, rxa->datum, rxa->datum_len); |
| } |
} |
| ndx = rsync_xal_l.count; /* pre-incremented count */ | ndx = rsync_xal_store(sxp->xattr); /* adds item to rsync_xal_l */ |
| rsync_xal_store(sxp->xattr); /* adds item to rsync_xal_l */ | |
| } |
} |
| |
|
| return ndx; |
return ndx; |
|
Line 464 int send_xattr(int f, stat_x *sxp)
|
Line 617 int send_xattr(int f, stat_x *sxp)
|
| * need so that send_xattr_request() can tell the sender about them. */ |
* need so that send_xattr_request() can tell the sender about them. */ |
| int xattr_diff(struct file_struct *file, stat_x *sxp, int find_all) |
int xattr_diff(struct file_struct *file, stat_x *sxp, int find_all) |
| { |
{ |
| item_list *lst = rsync_xal_l.items; | const rsync_xa_list *glst = rsync_xal_l.items; |
| | const item_list *lst; |
| rsync_xa *snd_rxa, *rec_rxa; |
rsync_xa *snd_rxa, *rec_rxa; |
| int snd_cnt, rec_cnt; |
int snd_cnt, rec_cnt; |
| int cmp, same, xattrs_equal = 1; |
int cmp, same, xattrs_equal = 1; |
|
Line 477 int xattr_diff(struct file_struct *file, stat_x *sxp,
|
Line 631 int xattr_diff(struct file_struct *file, stat_x *sxp,
|
| rec_cnt = 0; |
rec_cnt = 0; |
| } |
} |
| |
|
| if (F_XATTR(file) >= 0) | if (F_XATTR(file) >= 0) { |
| lst += F_XATTR(file); | glst += F_XATTR(file); |
| else | lst = &glst->xa_items; |
| | } else |
| lst = &empty_xattr; |
lst = &empty_xattr; |
| |
|
| snd_rxa = lst->items; |
snd_rxa = lst->items; |
|
Line 538 int xattr_diff(struct file_struct *file, stat_x *sxp,
|
Line 693 int xattr_diff(struct file_struct *file, stat_x *sxp,
|
| * XSTATE_ABBREV states into XSTATE_DONE. */ |
* XSTATE_ABBREV states into XSTATE_DONE. */ |
| void send_xattr_request(const char *fname, struct file_struct *file, int f_out) |
void send_xattr_request(const char *fname, struct file_struct *file, int f_out) |
| { |
{ |
| item_list *lst = rsync_xal_l.items; | const rsync_xa_list *glst = rsync_xal_l.items; |
| | const item_list *lst; |
| int cnt, prior_req = 0; |
int cnt, prior_req = 0; |
| rsync_xa *rxa; |
rsync_xa *rxa; |
| |
|
| lst += F_XATTR(file); | glst += F_XATTR(file); |
| | lst = &glst->xa_items; |
| | |
| for (rxa = lst->items, cnt = lst->count; cnt--; rxa++) { |
for (rxa = lst->items, cnt = lst->count; cnt--; rxa++) { |
| if (rxa->datum_len <= MAX_FULL_DATUM) |
if (rxa->datum_len <= MAX_FULL_DATUM) |
| continue; |
continue; |
|
Line 572 void send_xattr_request(const char *fname, struct file
|
Line 730 void send_xattr_request(const char *fname, struct file
|
| |
|
| /* Re-read the long datum. */ |
/* Re-read the long datum. */ |
| if (!(ptr = get_xattr_data(fname, rxa->name, &len, 0))) { |
if (!(ptr = get_xattr_data(fname, rxa->name, &len, 0))) { |
| rprintf(FERROR_XFER, "failed to re-read xattr %s for %s\n", rxa->name, fname); | if (errno != ENOTSUP && errno != ENOATTR) |
| | rprintf(FERROR_XFER, "failed to re-read xattr %s for %s\n", rxa->name, fname); |
| write_varint(f_out, 0); |
write_varint(f_out, 0); |
| continue; |
continue; |
| } |
} |
| |
|
| |
assert(ptr != UNREAD_DATA); |
| write_varint(f_out, len); /* length might have changed! */ |
write_varint(f_out, len); /* length might have changed! */ |
| write_buf(f_out, ptr, len); | write_bigbuf(f_out, ptr, len); |
| free(ptr); |
free(ptr); |
| } |
} |
| } |
} |
|
Line 593 void send_xattr_request(const char *fname, struct file
|
Line 753 void send_xattr_request(const char *fname, struct file
|
| * stores it in place of its checksum. */ |
* stores it in place of its checksum. */ |
| int recv_xattr_request(struct file_struct *file, int f_in) |
int recv_xattr_request(struct file_struct *file, int f_in) |
| { |
{ |
| item_list *lst = rsync_xal_l.items; | const rsync_xa_list *glst = rsync_xal_l.items; |
| | const item_list *lst; |
| char *old_datum, *name; |
char *old_datum, *name; |
| rsync_xa *rxa; |
rsync_xa *rxa; |
| int rel_pos, cnt, num, got_xattr_data = 0; |
int rel_pos, cnt, num, got_xattr_data = 0; |
|
Line 602 int recv_xattr_request(struct file_struct *file, int f
|
Line 763 int recv_xattr_request(struct file_struct *file, int f
|
| rprintf(FERROR, "recv_xattr_request: internal data error!\n"); |
rprintf(FERROR, "recv_xattr_request: internal data error!\n"); |
| exit_cleanup(RERR_PROTOCOL); |
exit_cleanup(RERR_PROTOCOL); |
| } |
} |
| lst += F_XATTR(file); | glst += F_XATTR(file); |
| | lst = &glst->xa_items; |
| |
|
| cnt = lst->count; |
cnt = lst->count; |
| rxa = lst->items; |
rxa = lst->items; |
| num = 0; |
num = 0; |
| while ((rel_pos = read_varint(f_in)) != 0) { |
while ((rel_pos = read_varint(f_in)) != 0) { |
| num += rel_pos; |
num += rel_pos; |
| while (cnt && rxa->num < num) { | if (am_sender) { |
| rxa++; | /* The sender-related num values are only in order on the sender. |
| cnt--; | * We use that order here to scan forward or backward as needed. */ |
| | if (rel_pos < 0) { |
| | while (cnt < (int)lst->count && rxa->num > num) { |
| | rxa--; |
| | cnt++; |
| | } |
| | } else { |
| | while (cnt > 1 && rxa->num < num) { |
| | rxa++; |
| | cnt--; |
| | } |
| | } |
| | } else { |
| | int j; |
| | /* The receiving side has no known num order, so we just scan |
| | * forward (w/wrap) and hope that the next value is near by. */ |
| | for (j = lst->count; j > 1 && rxa->num != num; j--) { |
| | if (--cnt) |
| | rxa++; |
| | else { |
| | cnt = lst->count; |
| | rxa = lst->items; |
| | } |
| | } |
| } |
} |
| if (!cnt || rxa->num != num) { |
if (!cnt || rxa->num != num) { |
| rprintf(FERROR, "[%s] could not find xattr #%d for %s\n", |
rprintf(FERROR, "[%s] could not find xattr #%d for %s\n", |
|
Line 632 int recv_xattr_request(struct file_struct *file, int f
|
Line 817 int recv_xattr_request(struct file_struct *file, int f
|
| old_datum = rxa->datum; |
old_datum = rxa->datum; |
| rxa->datum_len = read_varint(f_in); |
rxa->datum_len = read_varint(f_in); |
| |
|
| if (rxa->name_len + rxa->datum_len < rxa->name_len) | if (SIZE_MAX - rxa->name_len < rxa->datum_len) |
| overflow_exit("recv_xattr_request"); |
overflow_exit("recv_xattr_request"); |
| rxa->datum = new_array(char, rxa->datum_len + rxa->name_len); |
rxa->datum = new_array(char, rxa->datum_len + rxa->name_len); |
| if (!rxa->datum) |
|
| out_of_memory("recv_xattr_request"); |
|
| name = rxa->datum + rxa->datum_len; |
name = rxa->datum + rxa->datum_len; |
| memcpy(name, rxa->name, rxa->name_len); |
memcpy(name, rxa->name, rxa->name_len); |
| rxa->name = name; |
rxa->name = name; |
|
Line 665 void receive_xattr(int f, struct file_struct *file)
|
Line 848 void receive_xattr(int f, struct file_struct *file)
|
| if (ndx < 0 || (size_t)ndx > rsync_xal_l.count) { |
if (ndx < 0 || (size_t)ndx > rsync_xal_l.count) { |
| rprintf(FERROR, "receive_xattr: xa index %d out of" |
rprintf(FERROR, "receive_xattr: xa index %d out of" |
| " range for %s\n", ndx, f_name(file, NULL)); |
" range for %s\n", ndx, f_name(file, NULL)); |
| exit_cleanup(RERR_PROTOCOL); | exit_cleanup(RERR_STREAMIO); |
| } |
} |
| |
|
| if (ndx != 0) { |
if (ndx != 0) { |
|
Line 685 void receive_xattr(int f, struct file_struct *file)
|
Line 868 void receive_xattr(int f, struct file_struct *file)
|
| size_t datum_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 dget_len = datum_len > MAX_FULL_DATUM ? 1 + MAX_DIGEST_LEN : datum_len; |
| size_t extra_len = MIGHT_NEED_RPRE ? RPRE_LEN : 0; |
size_t extra_len = MIGHT_NEED_RPRE ? RPRE_LEN : 0; |
| if ((dget_len + extra_len < dget_len) | if (SIZE_MAX - dget_len < extra_len || SIZE_MAX - dget_len - extra_len < name_len) |
| || (dget_len + extra_len + name_len < dget_len)) | |
| overflow_exit("receive_xattr"); |
overflow_exit("receive_xattr"); |
| ptr = new_array(char, dget_len + extra_len + name_len); |
ptr = new_array(char, dget_len + extra_len + name_len); |
| if (!ptr) |
|
| out_of_memory("receive_xattr"); |
|
| name = ptr + dget_len + extra_len; |
name = ptr + dget_len + extra_len; |
| read_buf(f, name, name_len); |
read_buf(f, name, name_len); |
| |
if (name_len < 1 || name[name_len-1] != '\0') { |
| |
rprintf(FERROR, "Invalid xattr name received (missing trailing \\0).\n"); |
| |
exit_cleanup(RERR_FILEIO); |
| |
} |
| if (dget_len == datum_len) |
if (dget_len == datum_len) |
| read_buf(f, ptr, dget_len); |
read_buf(f, ptr, dget_len); |
| else { |
else { |
| *ptr = XSTATE_ABBREV; |
*ptr = XSTATE_ABBREV; |
| read_buf(f, ptr + 1, MAX_DIGEST_LEN); |
read_buf(f, ptr + 1, MAX_DIGEST_LEN); |
| } |
} |
| |
|
| |
if (saw_xattr_filter) { |
| |
if (name_is_excluded(name, NAME_IS_XATTR, ALL_FILTERS)) { |
| |
free(ptr); |
| |
continue; |
| |
} |
| |
} |
| #ifdef HAVE_LINUX_XATTRS |
#ifdef HAVE_LINUX_XATTRS |
| /* Non-root can only save the user namespace. */ |
/* Non-root can only save the user namespace. */ |
| if (am_root <= 0 && !HAS_PREFIX(name, USER_PREFIX)) { |
if (am_root <= 0 && !HAS_PREFIX(name, USER_PREFIX)) { |
| if (!am_root) { | if (!am_root && !saw_xattr_filter) { |
| free(ptr); |
free(ptr); |
| continue; |
continue; |
| } |
} |
|
Line 733 void receive_xattr(int f, struct file_struct *file)
|
Line 924 void receive_xattr(int f, struct file_struct *file)
|
| free(ptr); |
free(ptr); |
| continue; |
continue; |
| } |
} |
| |
|
| rxa = EXPAND_ITEM_LIST(&temp_xattr, rsync_xa, 1); |
rxa = EXPAND_ITEM_LIST(&temp_xattr, rsync_xa, 1); |
| rxa->name = name; |
rxa->name = name; |
| rxa->datum = ptr; |
rxa->datum = ptr; |
|
Line 744 void receive_xattr(int f, struct file_struct *file)
|
Line 936 void receive_xattr(int f, struct file_struct *file)
|
| if (need_sort && count > 1) |
if (need_sort && count > 1) |
| qsort(temp_xattr.items, count, sizeof (rsync_xa), rsync_xal_compare_names); |
qsort(temp_xattr.items, count, sizeof (rsync_xa), rsync_xal_compare_names); |
| |
|
| ndx = rsync_xal_l.count; /* pre-incremented count */ | ndx = rsync_xal_store(&temp_xattr); /* adds item to rsync_xal_l */ |
| rsync_xal_store(&temp_xattr); /* adds item to rsync_xal_l */ | |
| |
|
| F_XATTR(file) = ndx; |
F_XATTR(file) = ndx; |
| } |
} |
|
Line 771 void cache_tmp_xattr(struct file_struct *file, stat_x
|
Line 962 void cache_tmp_xattr(struct file_struct *file, stat_x
|
| void uncache_tmp_xattrs(void) |
void uncache_tmp_xattrs(void) |
| { |
{ |
| if (prior_xattr_count != (size_t)-1) { |
if (prior_xattr_count != (size_t)-1) { |
| item_list *xattr_item = rsync_xal_l.items; | rsync_xa_list *xa_list_item = rsync_xal_l.items; |
| item_list *xattr_start = xattr_item + prior_xattr_count; | rsync_xa_list *xa_list_start = xa_list_item + prior_xattr_count; |
| xattr_item += rsync_xal_l.count; | xa_list_item += rsync_xal_l.count; |
| rsync_xal_l.count = prior_xattr_count; |
rsync_xal_l.count = prior_xattr_count; |
| while (xattr_item-- > xattr_start) | while (xa_list_item-- > xa_list_start) { |
| rsync_xal_free(xattr_item); | struct ht_int64_node *node; |
| | rsync_xa_list_ref *ref; |
| | |
| | rsync_xal_free(&xa_list_item->xa_items); |
| | |
| | if (rsync_xal_h == NULL) |
| | continue; |
| | |
| | node = hashtable_find(rsync_xal_h, xa_list_item->key, NULL); |
| | if (node == NULL) |
| | continue; |
| | |
| | if (node->data == NULL) |
| | continue; |
| | |
| | ref = node->data; |
| | if (xa_list_item->ndx == ref->ndx) { |
| | /* xa_list_item is the first in the list. */ |
| | node->data = ref->next; |
| | free(ref); |
| | continue; |
| | } |
| | |
| | while (1) { |
| | rsync_xa_list_ref *next = ref->next; |
| | if (next == NULL) |
| | break; |
| | if (xa_list_item->ndx == next->ndx) { |
| | ref->next = next->next; |
| | free(next); |
| | break; |
| | } |
| | ref = next; |
| | } |
| | } |
| prior_xattr_count = (size_t)-1; |
prior_xattr_count = (size_t)-1; |
| } |
} |
| } |
} |
|
Line 792 static int rsync_xal_set(const char *fname, item_list
|
Line 1017 static int rsync_xal_set(const char *fname, item_list
|
| int user_only = am_root <= 0; |
int user_only = am_root <= 0; |
| #endif |
#endif |
| size_t name_len; |
size_t name_len; |
| int ret = 0; | int flags, ret = 0; |
| |
|
| /* This puts the current name list into the "namebuf" buffer. */ |
/* This puts the current name list into the "namebuf" buffer. */ |
| if ((list_len = get_xattr_names(fname)) < 0) |
if ((list_len = get_xattr_names(fname)) < 0) |
|
Line 802 static int rsync_xal_set(const char *fname, item_list
|
Line 1027 static int rsync_xal_set(const char *fname, item_list
|
| name = rxas[i].name; |
name = rxas[i].name; |
| |
|
| if (XATTR_ABBREV(rxas[i])) { |
if (XATTR_ABBREV(rxas[i])) { |
| |
int sum_len; |
| /* See if the fnamecmp version is identical. */ |
/* See if the fnamecmp version is identical. */ |
| len = name_len = rxas[i].name_len; |
len = name_len = rxas[i].name_len; |
| if ((ptr = get_xattr_data(fnamecmp, name, &len, 1)) == NULL) { | flags = GXD_OMIT_COMPRESSED | GXD_NO_MISSING_ERROR; |
| | if (preserve_hfs_compression && sxp->st.st_flags & UF_COMPRESSED) |
| | flags |= GXD_FILE_IS_COMPRESSED; |
| | if ((ptr = get_xattr_data(fnamecmp, name, &len, flags)) == NULL) { |
| still_abbrev: |
still_abbrev: |
| if (am_generator) |
if (am_generator) |
| continue; |
continue; |
|
Line 813 static int rsync_xal_set(const char *fname, item_list
|
Line 1042 static int rsync_xal_set(const char *fname, item_list
|
| ret = -1; |
ret = -1; |
| continue; |
continue; |
| } |
} |
| |
if (ptr == UNREAD_DATA) |
| |
continue; /* XXX Is this right? */ |
| if (len != rxas[i].datum_len) { |
if (len != rxas[i].datum_len) { |
| free(ptr); |
free(ptr); |
| goto still_abbrev; |
goto still_abbrev; |
| } |
} |
| |
|
| sum_init(checksum_seed); | sum_init(-1, checksum_seed); |
| sum_update(ptr, len); |
sum_update(ptr, len); |
| sum_end(sum); | sum_len = sum_end(sum); |
| if (memcmp(sum, rxas[i].datum + 1, MAX_DIGEST_LEN) != 0) { | if (memcmp(sum, rxas[i].datum + 1, sum_len) != 0) { |
| free(ptr); |
free(ptr); |
| goto still_abbrev; |
goto still_abbrev; |
| } |
} |
|
Line 830 static int rsync_xal_set(const char *fname, item_list
|
Line 1061 static int rsync_xal_set(const char *fname, item_list
|
| ; /* Value is already set when identical */ |
; /* Value is already set when identical */ |
| else if (sys_lsetxattr(fname, name, ptr, len) < 0) { |
else if (sys_lsetxattr(fname, name, ptr, len) < 0) { |
| rsyserr(FERROR_XFER, errno, |
rsyserr(FERROR_XFER, errno, |
| "rsync_xal_set: lsetxattr(\"%s\",\"%s\") failed", | "rsync_xal_set: lsetxattr(%s,\"%s\") failed", |
| full_fname(fname), name); |
full_fname(fname), name); |
| ret = -1; |
ret = -1; |
| } else /* make sure caller sets mtime */ |
} else /* make sure caller sets mtime */ |
|
Line 851 static int rsync_xal_set(const char *fname, item_list
|
Line 1082 static int rsync_xal_set(const char *fname, item_list
|
| |
|
| if (sys_lsetxattr(fname, name, rxas[i].datum, rxas[i].datum_len) < 0) { |
if (sys_lsetxattr(fname, name, rxas[i].datum, rxas[i].datum_len) < 0) { |
| rsyserr(FERROR_XFER, errno, |
rsyserr(FERROR_XFER, errno, |
| "rsync_xal_set: lsetxattr(\"%s\",\"%s\") failed", | "rsync_xal_set: lsetxattr(%s,\"%s\") failed", |
| full_fname(fname), name); |
full_fname(fname), name); |
| ret = -1; |
ret = -1; |
| } else /* make sure caller sets mtime */ |
} else /* make sure caller sets mtime */ |
|
Line 863 static int rsync_xal_set(const char *fname, item_list
|
Line 1094 static int rsync_xal_set(const char *fname, item_list
|
| name_len = strlen(name) + 1; |
name_len = strlen(name) + 1; |
| list_len -= name_len; |
list_len -= name_len; |
| |
|
| |
if (saw_xattr_filter) { |
| |
if (name_is_excluded(name, NAME_IS_XATTR, ALL_FILTERS)) |
| |
continue; |
| |
} |
| #ifdef HAVE_LINUX_XATTRS |
#ifdef HAVE_LINUX_XATTRS |
| /* We always ignore the system namespace, and non-root | /* Choose between ignoring the system namespace or (non-root) ignoring any non-user namespace. */ |
| * ignores everything but the user namespace. */ | else if (user_only ? !HAS_PREFIX(name, USER_PREFIX) : HAS_PREFIX(name, SYSTEM_PREFIX)) |
| if (user_only ? !HAS_PREFIX(name, USER_PREFIX) | |
| : HAS_PREFIX(name, SYSTEM_PREFIX)) | |
| continue; |
continue; |
| #endif |
#endif |
| if (am_root < 0 && name_len > RPRE_LEN | if (am_root < 0 && name_len > RPRE_LEN && name[RPRE_LEN] == '%' && strcmp(name, XSTAT_ATTR) == 0) |
| && name[RPRE_LEN] == '%' && strcmp(name, XSTAT_ATTR) == 0) | |
| continue; |
continue; |
| |
|
| for (i = 0; i < xalp->count; i++) { |
for (i = 0; i < xalp->count; i++) { |
|
Line 881 static int rsync_xal_set(const char *fname, item_list
|
Line 1113 static int rsync_xal_set(const char *fname, item_list
|
| if (i == xalp->count) { |
if (i == xalp->count) { |
| if (sys_lremovexattr(fname, name) < 0) { |
if (sys_lremovexattr(fname, name) < 0) { |
| rsyserr(FERROR_XFER, errno, |
rsyserr(FERROR_XFER, errno, |
| "rsync_xal_set: lremovexattr(\"%s\",\"%s\") failed", | "rsync_xal_set: lremovexattr(%s,\"%s\") failed", |
| full_fname(fname), name); |
full_fname(fname), name); |
| ret = -1; |
ret = -1; |
| } else /* make sure caller sets mtime */ |
} else /* make sure caller sets mtime */ |
|
Line 889 static int rsync_xal_set(const char *fname, item_list
|
Line 1121 static int rsync_xal_set(const char *fname, item_list
|
| } |
} |
| } |
} |
| |
|
| |
#ifdef HAVE_OSX_XATTRS |
| |
rsync_xal_free(xalp); /* Free this because we aren't using find_matching_xattr(). */ |
| |
#endif |
| |
|
| return ret; |
return ret; |
| } |
} |
| |
|
| /* Set extended attributes on indicated filename. */ |
/* Set extended attributes on indicated filename. */ |
| int set_xattr(const char *fname, const struct file_struct *file, | int set_xattr(const char *fname, const struct file_struct *file, const char *fnamecmp, stat_x *sxp) |
| const char *fnamecmp, stat_x *sxp) | |
| { |
{ |
| |
rsync_xa_list *glst = rsync_xal_l.items; |
| |
item_list *lst; |
| int ndx; |
int ndx; |
| item_list *lst = rsync_xal_l.items; |
|
| |
|
| if (dry_run) |
if (dry_run) |
| return 1; /* FIXME: --dry-run needs to compute this value */ |
return 1; /* FIXME: --dry-run needs to compute this value */ |
|
Line 927 int set_xattr(const char *fname, const struct file_str
|
Line 1163 int set_xattr(const char *fname, const struct file_str
|
| #endif |
#endif |
| |
|
| ndx = F_XATTR(file); |
ndx = F_XATTR(file); |
| return rsync_xal_set(fname, lst + ndx, fnamecmp, sxp); | glst += ndx; |
| | lst = &glst->xa_items; |
| | return rsync_xal_set(fname, lst, fnamecmp, sxp); |
| } |
} |
| |
|
| #ifdef SUPPORT_ACLS |
#ifdef SUPPORT_ACLS |
|
Line 935 char *get_xattr_acl(const char *fname, int is_access_a
|
Line 1173 char *get_xattr_acl(const char *fname, int is_access_a
|
| { |
{ |
| const char *name = is_access_acl ? XACC_ACL_ATTR : XDEF_ACL_ATTR; |
const char *name = is_access_acl ? XACC_ACL_ATTR : XDEF_ACL_ATTR; |
| *len_p = 0; /* no extra data alloc needed from get_xattr_data() */ |
*len_p = 0; /* no extra data alloc needed from get_xattr_data() */ |
| return get_xattr_data(fname, name, len_p, 1); | return get_xattr_data(fname, name, len_p, GXD_NO_MISSING_ERROR); |
| } |
} |
| |
|
| int set_xattr_acl(const char *fname, int is_access_acl, const char *buf, size_t buf_len) |
int set_xattr_acl(const char *fname, int is_access_acl, const char *buf, size_t buf_len) |
|
Line 943 int set_xattr_acl(const char *fname, int is_access_acl
|
Line 1181 int set_xattr_acl(const char *fname, int is_access_acl
|
| const char *name = is_access_acl ? XACC_ACL_ATTR : XDEF_ACL_ATTR; |
const char *name = is_access_acl ? XACC_ACL_ATTR : XDEF_ACL_ATTR; |
| if (sys_lsetxattr(fname, name, buf, buf_len) < 0) { |
if (sys_lsetxattr(fname, name, buf, buf_len) < 0) { |
| rsyserr(FERROR_XFER, errno, |
rsyserr(FERROR_XFER, errno, |
| "set_xattr_acl: lsetxattr(\"%s\",\"%s\") failed", | "set_xattr_acl: lsetxattr(%s,\"%s\") failed", |
| full_fname(fname), name); |
full_fname(fname), name); |
| return -1; |
return -1; |
| } |
} |
|
Line 956 int del_def_xattr_acl(const char *fname)
|
Line 1194 int del_def_xattr_acl(const char *fname)
|
| } |
} |
| #endif |
#endif |
| |
|
| |
int get_sum_xattr(const char *fname, STRUCT_STAT *stp, char *sum) |
| |
{ |
| |
const char *mdattr = checksum_type == 5 ? MD5_ATTR : MD4_ATTR; |
| |
char buf[256]; |
| |
uint32 file_length, mtime; |
| |
int len; |
| |
|
| |
len = sys_lgetxattr(fname, mdattr, buf, sizeof buf); |
| |
if (len < 0) { |
| |
if (errno == ENOTSUP || errno == ENOATTR) |
| |
return 0; |
| |
rsyserr(FERROR_XFER, errno, "failed to read xattr %s for %s", |
| |
mdattr, full_fname(fname)); |
| |
return 0; |
| |
} |
| |
if (len != 4 + 4 + flist_csum_len) { |
| |
rprintf(FERROR, "Corrupt %s xattr attached to %s -- skipping\n", |
| |
mdattr, full_fname(fname)); |
| |
return 0; |
| |
} |
| |
|
| |
file_length = IVAL(buf, 0); /* 32-bit values -- trunctions are OK */ |
| |
mtime = IVAL(buf, 4); |
| |
|
| |
if ((uint32)stp->st_size != file_length || (uint32)stp->st_mtime != mtime) |
| |
return 0; |
| |
|
| |
memcpy(sum, buf + 8, flist_csum_len); |
| |
|
| |
return 1; |
| |
} |
| |
|
| int get_stat_xattr(const char *fname, int fd, STRUCT_STAT *fst, STRUCT_STAT *xst) |
int get_stat_xattr(const char *fname, int fd, STRUCT_STAT *fst, STRUCT_STAT *xst) |
| { |
{ |
| int mode, rdev_major, rdev_minor, uid, gid, len; |
int mode, rdev_major, rdev_minor, uid, gid, len; |
|
Line 1042 int set_stat_xattr(const char *fname, struct file_stru
|
Line 1312 int set_stat_xattr(const char *fname, struct file_stru
|
| mode = (fst.st_mode & _S_IFMT) | (fmode & ACCESSPERMS) |
mode = (fst.st_mode & _S_IFMT) | (fmode & ACCESSPERMS) |
| | (S_ISDIR(fst.st_mode) ? 0700 : 0600); |
| (S_ISDIR(fst.st_mode) ? 0700 : 0600); |
| if (fst.st_mode != mode) |
if (fst.st_mode != mode) |
| do_chmod(fname, mode); | do_chmod(fname, mode, ST_FLAGS(fst)); |
| if (!IS_DEVICE(fst.st_mode)) |
if (!IS_DEVICE(fst.st_mode)) |
| fst.st_rdev = 0; /* just in case */ |
fst.st_rdev = 0; /* just in case */ |
| |
|
|
Line 1078 int set_stat_xattr(const char *fname, struct file_stru
|
Line 1348 int set_stat_xattr(const char *fname, struct file_stru
|
| return 0; |
return 0; |
| } |
} |
| |
|
| |
#ifdef SUPPORT_HFS_COMPRESSION |
| |
static inline void hfs_compress_tweaks(STRUCT_STAT *fst) |
| |
{ |
| |
if (fst->st_flags & UF_COMPRESSED) { |
| |
if (preserve_hfs_compression) { |
| |
/* We're sending the compression xattr, not the decompressed data fork. |
| |
* Setting rsync's idea of the file size to 0 effectively prevents the |
| |
* transfer of the data fork. */ |
| |
fst->st_size = 0; |
| |
} else { |
| |
/* If the sender's filesystem supports compression, then we'll be able |
| |
* to send the decompressed data fork and the decmpfs xattr will be |
| |
* hidden (not sent). As such, we need to strip the compression flag. */ |
| |
fst->st_flags &= ~UF_COMPRESSED; |
| |
} |
| |
} |
| |
} |
| |
#endif |
| |
|
| int x_stat(const char *fname, STRUCT_STAT *fst, STRUCT_STAT *xst) |
int x_stat(const char *fname, STRUCT_STAT *fst, STRUCT_STAT *xst) |
| { |
{ |
| int ret = do_stat(fname, fst); |
int ret = do_stat(fname, fst); |
| if ((ret < 0 || get_stat_xattr(fname, -1, fst, xst) < 0) && xst) |
if ((ret < 0 || get_stat_xattr(fname, -1, fst, xst) < 0) && xst) |
| xst->st_mode = 0; |
xst->st_mode = 0; |
| |
#ifdef SUPPORT_HFS_COMPRESSION |
| |
hfs_compress_tweaks(fst); |
| |
#endif |
| return ret; |
return ret; |
| } |
} |
| |
|
|
Line 1091 int x_lstat(const char *fname, STRUCT_STAT *fst, STRUC
|
Line 1383 int x_lstat(const char *fname, STRUCT_STAT *fst, STRUC
|
| int ret = do_lstat(fname, fst); |
int ret = do_lstat(fname, fst); |
| if ((ret < 0 || get_stat_xattr(fname, -1, fst, xst) < 0) && xst) |
if ((ret < 0 || get_stat_xattr(fname, -1, fst, xst) < 0) && xst) |
| xst->st_mode = 0; |
xst->st_mode = 0; |
| |
#ifdef SUPPORT_HFS_COMPRESSION |
| |
hfs_compress_tweaks(fst); |
| |
#endif |
| return ret; |
return ret; |
| } |
} |
| |
|
|
Line 1099 int x_fstat(int fd, STRUCT_STAT *fst, STRUCT_STAT *xst
|
Line 1394 int x_fstat(int fd, STRUCT_STAT *fst, STRUCT_STAT *xst
|
| int ret = do_fstat(fd, fst); |
int ret = do_fstat(fd, fst); |
| if ((ret < 0 || get_stat_xattr(NULL, fd, fst, xst) < 0) && xst) |
if ((ret < 0 || get_stat_xattr(NULL, fd, fst, xst) < 0) && xst) |
| xst->st_mode = 0; |
xst->st_mode = 0; |
| |
#ifdef SUPPORT_HFS_COMPRESSION |
| |
hfs_compress_tweaks(fst); |
| |
#endif |
| return ret; |
return ret; |
| } |
} |
| |
|