File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / xattrs.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 00:32:36 2021 UTC (3 years, 3 months ago) by misho
Branches: rsync, MAIN
CVS tags: v3_2_3, HEAD
rsync 3.2.3

    1: /*
    2:  * Extended Attribute support for rsync.
    3:  * Written by Jay Fenlason, vaguely based on the ACLs patch.
    4:  *
    5:  * Copyright (C) 2004 Red Hat, Inc.
    6:  * Copyright (C) 2006-2020 Wayne Davison
    7:  *
    8:  * This program is free software; you can redistribute it and/or modify
    9:  * it under the terms of the GNU General Public License as published by
   10:  * the Free Software Foundation; either version 3 of the License, or
   11:  * (at your option) any later version.
   12:  *
   13:  * This program is distributed in the hope that it will be useful,
   14:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   15:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16:  * GNU General Public License for more details.
   17:  *
   18:  * You should have received a copy of the GNU General Public License along
   19:  * with this program; if not, visit the http://fsf.org website.
   20:  */
   21: 
   22: #include "rsync.h"
   23: #include "ifuncs.h"
   24: #include "inums.h"
   25: #include "lib/sysxattrs.h"
   26: 
   27: #ifdef SUPPORT_XATTRS
   28: 
   29: extern int dry_run;
   30: extern int am_root;
   31: extern int am_sender;
   32: extern int am_generator;
   33: extern int read_only;
   34: extern int list_only;
   35: extern int preserve_xattrs;
   36: extern int preserve_hfs_compression;
   37: extern int preserve_links;
   38: extern int preserve_devices;
   39: extern int preserve_specials;
   40: extern int checksum_type;
   41: extern int checksum_seed;
   42: extern int flist_csum_len;
   43: extern int saw_xattr_filter;
   44: 
   45: #define RSYNC_XAL_INITIAL 5
   46: #define RSYNC_XAL_LIST_INITIAL 100
   47: 
   48: #define GXD_NO_MISSING_ERROR (1<<0)
   49: #define GXD_OMIT_COMPRESSED (1<<1)
   50: #define GXD_FILE_IS_COMPRESSED (1<<2)
   51: 
   52: #define MAX_FULL_DATUM 32
   53: 
   54: #define HAS_PREFIX(str, prfx) (*(str) == *(prfx) && strncmp(str, prfx, sizeof (prfx) - 1) == 0)
   55: 
   56: #define XATTR_ABBREV(x) ((size_t)((x).name - (x).datum) < (x).datum_len)
   57: 
   58: #define XSTATE_ABBREV	1
   59: #define XSTATE_DONE	2
   60: #define XSTATE_TODO	3
   61: 
   62: #define USER_PREFIX "user."
   63: #define UPRE_LEN ((int)sizeof USER_PREFIX - 1)
   64: #define SYSTEM_PREFIX "system."
   65: #define SPRE_LEN ((int)sizeof SYSTEM_PREFIX - 1)
   66: 
   67: #ifdef HAVE_LINUX_XATTRS
   68: #define MIGHT_NEED_RPRE (am_root <= 0)
   69: #define RSYNC_PREFIX USER_PREFIX "rsync."
   70: #else
   71: #define MIGHT_NEED_RPRE am_root
   72: #define RSYNC_PREFIX "rsync."
   73: #endif
   74: #define RPRE_LEN ((int)sizeof RSYNC_PREFIX - 1)
   75: 
   76: #define XSTAT_SUFFIX "stat"
   77: #define XSTAT_ATTR RSYNC_PREFIX "%" XSTAT_SUFFIX
   78: #define XACC_ACL_SUFFIX "aacl"
   79: #define XACC_ACL_ATTR RSYNC_PREFIX "%" XACC_ACL_SUFFIX
   80: #define XDEF_ACL_SUFFIX "dacl"
   81: #define XDEF_ACL_ATTR RSYNC_PREFIX "%" XDEF_ACL_SUFFIX
   82: #define MD4_SUFFIX "md4"
   83: #define MD4_ATTR RSYNC_PREFIX "%" MD4_SUFFIX
   84: #define MD5_SUFFIX "md5"
   85: #define MD5_ATTR RSYNC_PREFIX "%" MD5_SUFFIX
   86: 
   87: #define APPLE_PREFIX "com.apple."
   88: #define APLPRE_LEN ((int)sizeof APPLE_PREFIX - 1)
   89: #define DECMPFS_SUFFIX "decmpfs"
   90: #define RESOURCEFORK_SUFFIX "ResourceFork"
   91: 
   92: #define UNREAD_DATA ((char *)1)
   93: 
   94: #if MAX_DIGEST_LEN < SIZEOF_TIME_T
   95: #error MAX_DIGEST_LEN is too small to hold an mtime
   96: #endif
   97: 
   98: typedef struct {
   99: 	char *datum, *name;
  100: 	size_t datum_len, name_len;
  101: 	int num;
  102: } rsync_xa;
  103: 
  104: struct _rsync_xa_list;
  105: 
  106: typedef struct _rsync_xa_list_ref {
  107: 	struct _rsync_xa_list_ref *next;
  108: 	int ndx;
  109: } rsync_xa_list_ref;
  110: 
  111: typedef struct _rsync_xa_list {
  112: 	int ndx;
  113: 	int64 key;
  114: 	item_list xa_items;
  115: } rsync_xa_list;
  116: 
  117: static size_t namebuf_len = 0;
  118: static char *namebuf = NULL;
  119: 
  120: static const rsync_xa_list empty_xa_list = {
  121: 	.xa_items = EMPTY_ITEM_LIST,
  122: };
  123: static const item_list empty_xattr = EMPTY_ITEM_LIST;
  124: static item_list rsync_xal_l = EMPTY_ITEM_LIST;
  125: static struct hashtable *rsync_xal_h = NULL;
  126: 
  127: static size_t prior_xattr_count = (size_t)-1;
  128: 
  129: /* ------------------------------------------------------------------------- */
  130: 
  131: static void rsync_xal_free(item_list *xalp)
  132: {
  133: 	size_t i;
  134: 	rsync_xa *rxas = xalp->items;
  135: 
  136: 	if (!xalp->malloced)
  137: 		return;
  138: 
  139: 	for (i = 0; i < xalp->count; i++) {
  140: 		free(rxas[i].datum);
  141: 		/*free(rxas[i].name);*/
  142: 	}
  143: 	free(xalp->items);
  144: }
  145: 
  146: void free_xattr(stat_x *sxp)
  147: {
  148: 	if (!sxp->xattr)
  149: 		return;
  150: 	rsync_xal_free(sxp->xattr);
  151: 	free(sxp->xattr);
  152: 	sxp->xattr = NULL;
  153: }
  154: 
  155: static int rsync_xal_compare_names(const void *x1, const void *x2)
  156: {
  157: 	const rsync_xa *xa1 = x1;
  158: 	const rsync_xa *xa2 = x2;
  159: 	return strcmp(xa1->name, xa2->name);
  160: }
  161: 
  162: static ssize_t get_xattr_names(const char *fname)
  163: {
  164: 	ssize_t list_len;
  165: 	int64 arg;
  166: 
  167: 	if (!namebuf) {
  168: 		namebuf_len = 1024;
  169: 		namebuf = new_array(char, namebuf_len);
  170: 	}
  171: 
  172: 	while (1) {
  173: 		/* The length returned includes all the '\0' terminators. */
  174: 		list_len = sys_llistxattr(fname, namebuf, namebuf_len);
  175: 		if (list_len >= 0) {
  176: 			if ((size_t)list_len <= namebuf_len)
  177: 				break;
  178: 		} else if (errno == ENOTSUP)
  179: 			return 0;
  180: 		else if (errno != ERANGE) {
  181: 			arg = namebuf_len;
  182: 		  got_error:
  183: 			rsyserr(FERROR_XFER, errno,
  184: 				"get_xattr_names: llistxattr(%s,%s) failed",
  185: 				full_fname(fname), big_num(arg));
  186: 			return -1;
  187: 		}
  188: 		list_len = sys_llistxattr(fname, NULL, 0);
  189: 		if (list_len < 0) {
  190: 			arg = 0;
  191: 			goto got_error;
  192: 		}
  193: 		if (namebuf_len)
  194: 			free(namebuf);
  195: 		namebuf_len = list_len + 1024;
  196: 		namebuf = new_array(char, namebuf_len);
  197: 	}
  198: 
  199: 	return list_len;
  200: }
  201: 
  202: /* On entry, the *len_ptr parameter contains the size of the extra space we
  203:  * should allocate when we create a buffer for the data.  On exit, it contains
  204:  * the length of the datum. */
  205: static char *get_xattr_data(const char *fname, const char *name, size_t *len_ptr, int flags)
  206: {
  207: 	size_t datum_len = sys_lgetxattr(fname, name, NULL, 0);
  208: 	size_t extra_len = *len_ptr;
  209: 	char *ptr;
  210: 
  211: 	*len_ptr = datum_len;
  212: 
  213: 	if (datum_len == (size_t)-1) {
  214: 		if (errno == ENOTSUP || flags & GXD_NO_MISSING_ERROR)
  215: 			return NULL;
  216: 		rsyserr(FERROR_XFER, errno,
  217: 			"get_xattr_data: lgetxattr(%s,\"%s\",0) failed",
  218: 			full_fname(fname), name);
  219: 		return NULL;
  220: 	}
  221: 
  222: 	if (flags & GXD_OMIT_COMPRESSED && datum_len > MAX_FULL_DATUM
  223: 	 && HAS_PREFIX(name, APPLE_PREFIX)
  224: 	 && (strcmp(name+APLPRE_LEN, DECMPFS_SUFFIX) == 0
  225: 	  || (flags & GXD_FILE_IS_COMPRESSED && strcmp(name+APLPRE_LEN, RESOURCEFORK_SUFFIX) == 0))) {
  226: 		/* If we are omitting compress-file-related data, we don't want to
  227: 		 * actually read this data. */
  228: 		return UNREAD_DATA;
  229: 	}
  230: 
  231: 	if (!datum_len && !extra_len)
  232: 		extra_len = 1; /* request non-zero amount of memory */
  233: 	if (SIZE_MAX - datum_len < extra_len)
  234: 		overflow_exit("get_xattr_data");
  235: 	ptr = new_array(char, datum_len + extra_len);
  236: 
  237: 	if (datum_len) {
  238: 		size_t len = sys_lgetxattr(fname, name, ptr, datum_len);
  239: 		if (len != datum_len) {
  240: 			if (len == (size_t)-1) {
  241: 				rsyserr(FERROR_XFER, errno,
  242: 					"get_xattr_data: lgetxattr(%s,\"%s\",%ld) failed",
  243: 					full_fname(fname), name, (long)datum_len);
  244: 			} else {
  245: 				rprintf(FERROR_XFER,
  246: 					"get_xattr_data: lgetxattr(%s,\"%s\",%ld) returned %ld\n",
  247: 					full_fname(fname), name,
  248: 					(long)datum_len, (long)len);
  249: 			}
  250: 			free(ptr);
  251: 			return NULL;
  252: 		}
  253: 	}
  254: 
  255: 	return ptr;
  256: }
  257: 
  258: static void checksum_xattr_data(char *sum, const char *datum, size_t datum_len, stat_x *sxp)
  259: {
  260: 	if (datum == UNREAD_DATA) {
  261: 		/* For abbreviated compressed data, we store the file's mtime as the checksum. */
  262: 		SIVAL(sum, 0, sxp->st.st_mtime);
  263: #if SIZEOF_TIME_T > 4
  264: 		SIVAL(sum, 4, sxp->st.st_mtime >> 32);
  265: #if MAX_DIGEST_LEN > 8
  266: 		memset(sum + 8, 0, MAX_DIGEST_LEN - 8);
  267: #endif
  268: #else
  269: #if MAX_DIGEST_LEN > 4
  270: 		memset(sum + 4, 0, MAX_DIGEST_LEN - 4);
  271: #endif
  272: #endif
  273: 	} else {
  274: 		sum_init(-1, checksum_seed);
  275: 		sum_update(datum, datum_len);
  276: 		sum_end(sum);
  277: 	}
  278: }
  279: 
  280: $$$ERROR$$$ the old patch needs reworking since rsync_xal_get() has totally changed!
  281: 
  282: static int rsync_xal_get(const char *fname, stat_x *sxp)
  283: {
  284: 	ssize_t list_len, name_len;
  285: 	size_t datum_len, name_offset;
  286: 	char *name, *ptr;
  287: #ifdef HAVE_LINUX_XATTRS
  288: 	int user_only = am_sender ? 0 : !am_root;
  289: #endif
  290: 	rsync_xa *rxa;
  291: 	int count, flags;
  292: 	item_list *xalp = sxp->xattr;
  293: 
  294: 	/* This puts the name list into the "namebuf" buffer. */
  295: 	if ((list_len = get_xattr_names(fname)) < 0)
  296: 		return -1;
  297: 
  298: 	for (name = namebuf; list_len > 0; name += name_len) {
  299: 		name_len = strlen(name) + 1;
  300: 		list_len -= name_len;
  301: 
  302: 		if (saw_xattr_filter) {
  303: 			if (name_is_excluded(name, NAME_IS_XATTR, ALL_FILTERS))
  304: 				continue;
  305: 		}
  306: #ifdef HAVE_LINUX_XATTRS
  307: 		/* Choose between ignoring the system namespace or (non-root) ignoring any non-user namespace. */
  308: 		else if (user_only ? !HAS_PREFIX(name, USER_PREFIX) : HAS_PREFIX(name, SYSTEM_PREFIX))
  309: 			continue;
  310: #endif
  311: 
  312: 		/* No rsync.%FOO attributes are copied w/o 2 -X options. */
  313: 		if (name_len > RPRE_LEN && name[RPRE_LEN] == '%' && HAS_PREFIX(name, RSYNC_PREFIX)) {
  314: 			if ((am_sender && preserve_xattrs < 2)
  315: 			 || (am_root < 0
  316: 			  && (strcmp(name+RPRE_LEN+1, XSTAT_SUFFIX) == 0
  317: 			   || strcmp(name+RPRE_LEN+1, XACC_ACL_SUFFIX) == 0
  318: 			   || strcmp(name+RPRE_LEN+1, XDEF_ACL_SUFFIX) == 0
  319: 			   || strcmp(name+RPRE_LEN+1, MD4_SUFFIX) == 0
  320: 			   || strcmp(name+RPRE_LEN+1, MD5_SUFFIX) == 0)))
  321: 				continue;
  322: 		}
  323: 
  324: 		datum_len = name_len; /* Pass extra size to get_xattr_data() */
  325: 		flags = GXD_OMIT_COMPRESSED;
  326: 		if (preserve_hfs_compression && sxp->st.st_flags & UF_COMPRESSED)
  327: 			flags |= GXD_FILE_IS_COMPRESSED;
  328: 		if (!(ptr = get_xattr_data(fname, name, &datum_len, flags)))
  329: 			return -1;
  330: 
  331: 		if (datum_len > MAX_FULL_DATUM) {
  332: 			/* For large datums, we store a flag and a checksum. */
  333: 			char *datum = ptr;
  334: 			name_offset = 1 + MAX_DIGEST_LEN;
  335: 			sum_init(-1, checksum_seed);
  336: 			sum_update(ptr, datum_len);
  337: 			free(ptr);
  338: 
  339: 			ptr = new_array(char, name_offset + name_len);
  340: 			*ptr = XSTATE_ABBREV;
  341: 			checksum_xattr_data(ptr+1, datum, datum_len, sxp);
  342: 			if (datum != UNREAD_DATA)
  343: 				free(datum);
  344: 		} else
  345: 			name_offset = datum_len;
  346: 
  347: 		rxa = EXPAND_ITEM_LIST(xalp, rsync_xa, RSYNC_XAL_INITIAL);
  348: 		rxa->name = ptr + name_offset;
  349: 		memcpy(rxa->name, name, name_len);
  350: 		rxa->datum = ptr;
  351: 		rxa->name_len = name_len;
  352: 		rxa->datum_len = datum_len;
  353: 	}
  354: 	count = xalp->count;
  355: 	rxa = xalp->items;
  356: 	if (count > 1)
  357: 		qsort(rxa, count, sizeof (rsync_xa), rsync_xal_compare_names);
  358: 	for (rxa += count-1; count; count--, rxa--)
  359: 		rxa->num = count;
  360: 	return 0;
  361: }
  362: 
  363: /* Read the xattr(s) for this filename. */
  364: int get_xattr(const char *fname, stat_x *sxp)
  365: {
  366: 	sxp->xattr = new(item_list);
  367: 	*sxp->xattr = empty_xattr;
  368: 
  369: 	if (S_ISREG(sxp->st.st_mode) || S_ISDIR(sxp->st.st_mode)) {
  370: 		/* Everyone supports this. */
  371: 	} else if (S_ISLNK(sxp->st.st_mode)) {
  372: #ifndef NO_SYMLINK_XATTRS
  373: 		if (!preserve_links)
  374: #endif
  375: 			return 0;
  376: 	} else if (IS_SPECIAL(sxp->st.st_mode)) {
  377: #ifndef NO_SPECIAL_XATTRS
  378: 		if (!preserve_specials)
  379: #endif
  380: 			return 0;
  381: 	} else if (IS_DEVICE(sxp->st.st_mode)) {
  382: #ifndef NO_DEVICE_XATTRS
  383: 		if (!preserve_devices)
  384: #endif
  385: 			return 0;
  386: 	} else if (IS_MISSING_FILE(sxp->st))
  387: 		return 0;
  388: 
  389: 	if (rsync_xal_get(fname, sxp) < 0) {
  390: 		free_xattr(sxp);
  391: 		return -1;
  392: 	}
  393: 	return 0;
  394: }
  395: 
  396: int copy_xattrs(const char *source, const char *dest)
  397: {
  398: 	ssize_t list_len, name_len;
  399: 	size_t datum_len;
  400: 	char *name, *ptr;
  401: #ifdef HAVE_LINUX_XATTRS
  402: 	int user_only = am_sender ? 0 : am_root <= 0;
  403: #endif
  404: 
  405: 	/* This puts the name list into the "namebuf" buffer. */
  406: 	if ((list_len = get_xattr_names(source)) < 0)
  407: 		return -1;
  408: 
  409: 	for (name = namebuf; list_len > 0; name += name_len) {
  410: 		name_len = strlen(name) + 1;
  411: 		list_len -= name_len;
  412: 
  413: 		if (saw_xattr_filter) {
  414: 			if (name_is_excluded(name, NAME_IS_XATTR, ALL_FILTERS))
  415: 				continue;
  416: 		}
  417: #ifdef HAVE_LINUX_XATTRS
  418: 		/* Choose between ignoring the system namespace or (non-root) ignoring any non-user namespace. */
  419: 		else if (user_only ? !HAS_PREFIX(name, USER_PREFIX) : HAS_PREFIX(name, SYSTEM_PREFIX))
  420: 			continue;
  421: #endif
  422: 
  423: 		datum_len = 0;
  424: 		if (!(ptr = get_xattr_data(source, name, &datum_len, 0)))
  425: 			return -1;
  426: 		if (ptr == UNREAD_DATA)
  427: 			continue; /* XXX Is this right? */
  428: 		if (sys_lsetxattr(dest, name, ptr, datum_len) < 0) {
  429: 			int save_errno = errno ? errno : EINVAL;
  430: 			rsyserr(FERROR_XFER, errno,
  431: 				"copy_xattrs: lsetxattr(%s,\"%s\") failed",
  432: 				full_fname(dest), name);
  433: 			errno = save_errno;
  434: 			return -1;
  435: 		}
  436: 		free(ptr);
  437: 	}
  438: 
  439: 	return 0;
  440: }
  441: 
  442: static int64 xattr_lookup_hash(const item_list *xalp)
  443: {
  444: 	const rsync_xa *rxas = xalp->items;
  445: 	size_t i;
  446: 	int64 key = hashlittle(&xalp->count, sizeof xalp->count);
  447: 
  448: 	for (i = 0; i < xalp->count; i++) {
  449: 		key += hashlittle(rxas[i].name, rxas[i].name_len);
  450: 		if (rxas[i].datum_len > MAX_FULL_DATUM)
  451: 			key += hashlittle(rxas[i].datum, MAX_DIGEST_LEN);
  452: 		else
  453: 			key += hashlittle(rxas[i].datum, rxas[i].datum_len);
  454: 	}
  455: 
  456: 	if (key == 0) {
  457: 		/* This is very unlikely, but we should never
  458: 		 * return 0 as hashtable_find() doesn't like it. */
  459: 		return 1;
  460: 	}
  461: 
  462: 	return key;
  463: }
  464: 
  465: static int find_matching_xattr(const item_list *xalp)
  466: {
  467: 	const struct ht_int64_node *node;
  468: 	const rsync_xa_list_ref *ref;
  469: 	int64 key;
  470: 
  471: 	if (rsync_xal_h == NULL)
  472: 		return -1;
  473: 
  474: 	key = xattr_lookup_hash(xalp);
  475: 
  476: 	node = hashtable_find(rsync_xal_h, key, NULL);
  477: 	if (node == NULL)
  478: 		return -1;
  479: 
  480: 	if (node->data == NULL)
  481: 		return -1;
  482: 
  483: 	for (ref = node->data; ref != NULL; ref = ref->next) {
  484: 		const rsync_xa_list *ptr = rsync_xal_l.items;
  485: 		const rsync_xa *rxas1;
  486: 		const rsync_xa *rxas2 = xalp->items;
  487: 		size_t j;
  488: 
  489: 		ptr += ref->ndx;
  490: 		rxas1 = ptr->xa_items.items;
  491: 
  492: 		/* Wrong number of elements? */
  493: 		if (ptr->xa_items.count != xalp->count)
  494: 			continue;
  495: 		/* any elements different? */
  496: 		for (j = 0; j < xalp->count; j++) {
  497: 			if (rxas1[j].name_len != rxas2[j].name_len
  498: 			 || rxas1[j].datum_len != rxas2[j].datum_len
  499: 			 || strcmp(rxas1[j].name, rxas2[j].name))
  500: 				break;
  501: 			if (rxas1[j].datum_len > MAX_FULL_DATUM) {
  502: 				if (memcmp(rxas1[j].datum + 1,
  503: 					   rxas2[j].datum + 1,
  504: 					   MAX_DIGEST_LEN) != 0)
  505: 					break;
  506: 			} else {
  507: 				if (memcmp(rxas1[j].datum, rxas2[j].datum,
  508: 					   rxas2[j].datum_len))
  509: 					break;
  510: 			}
  511: 		}
  512: 		/* no differences found.  This is The One! */
  513: 		if (j == xalp->count)
  514: 			return ref->ndx;
  515: 	}
  516: 
  517: 	return -1;
  518: #endif
  519: }
  520: 
  521: /* Store *xalp on the end of rsync_xal_l */
  522: static int rsync_xal_store(item_list *xalp)
  523: {
  524: 	struct ht_int64_node *node;
  525: 	int ndx = rsync_xal_l.count; /* pre-incremented count */
  526: 	rsync_xa_list *new_list = EXPAND_ITEM_LIST(&rsync_xal_l, rsync_xa_list, RSYNC_XAL_LIST_INITIAL);
  527: 	rsync_xa_list_ref *new_ref;
  528: 	/* Since the following call starts a new list, we know it will hold the
  529: 	 * entire initial-count, not just enough space for one new item. */
  530: 	*new_list = empty_xa_list;
  531: 	(void)EXPAND_ITEM_LIST(&new_list->xa_items, rsync_xa, xalp->count);
  532: 	memcpy(new_list->xa_items.items, xalp->items, xalp->count * sizeof (rsync_xa));
  533: 	new_list->xa_items.count = xalp->count;
  534: 	xalp->count = 0;
  535: 
  536: 	new_list->ndx = ndx;
  537: 	new_list->key = xattr_lookup_hash(&new_list->xa_items);
  538: 
  539: 	if (rsync_xal_h == NULL)
  540: 		rsync_xal_h = hashtable_create(512, HT_KEY64);
  541: 	if (rsync_xal_h == NULL)
  542: 		out_of_memory("rsync_xal_h hashtable_create()");
  543: 
  544: 	new_ref = new0(rsync_xa_list_ref);
  545: 	new_ref->ndx = ndx;
  546: 
  547: 	node = hashtable_find(rsync_xal_h, new_list->key, new_ref);
  548: 	if (node->data != (void*)new_ref) {
  549: 		rsync_xa_list_ref *ref = node->data;
  550: 
  551: 		while (ref != NULL) {
  552: 			if (ref->next != NULL) {
  553: 				ref = ref->next;
  554: 				continue;
  555: 			}
  556: 
  557: 			ref->next = new_ref;
  558: 			break;
  559: 		}
  560: 	}
  561: 
  562: 	return ndx;
  563: }
  564: 
  565: /* Send the make_xattr()-generated xattr list for this flist entry. */
  566: int send_xattr(int f, stat_x *sxp)
  567: {
  568: 	int ndx = find_matching_xattr(sxp->xattr);
  569: 
  570: 	/* Send 0 (-1 + 1) to indicate that literal xattr data follows. */
  571: 	write_varint(f, ndx + 1);
  572: 
  573: 	if (ndx < 0) {
  574: 		rsync_xa *rxa;
  575: 		int count = sxp->xattr->count;
  576: 		write_varint(f, count);
  577: 		for (rxa = sxp->xattr->items; count--; rxa++) {
  578: 			size_t name_len = rxa->name_len;
  579: 			const char *name = rxa->name;
  580: 			/* Strip the rsync prefix from disguised namespaces. */
  581: 			if (name_len > RPRE_LEN
  582: #ifdef HAVE_LINUX_XATTRS
  583: 			 && am_root < 0
  584: #endif
  585: 			 && name[RPRE_LEN] != '%' && HAS_PREFIX(name, RSYNC_PREFIX)) {
  586: 				name += RPRE_LEN;
  587: 				name_len -= RPRE_LEN;
  588: 			}
  589: #ifndef HAVE_LINUX_XATTRS
  590: 			else {
  591: 				/* Put everything else in the user namespace. */
  592: 				name_len += UPRE_LEN;
  593: 			}
  594: #endif
  595: 			write_varint(f, name_len);
  596: 			write_varint(f, rxa->datum_len);
  597: #ifndef HAVE_LINUX_XATTRS
  598: 			if (name_len > rxa->name_len) {
  599: 				write_buf(f, USER_PREFIX, UPRE_LEN);
  600: 				name_len -= UPRE_LEN;
  601: 			}
  602: #endif
  603: 			write_buf(f, name, name_len);
  604: 			if (rxa->datum_len > MAX_FULL_DATUM)
  605: 				write_buf(f, rxa->datum + 1, MAX_DIGEST_LEN);
  606: 			else
  607: 				write_bigbuf(f, rxa->datum, rxa->datum_len);
  608: 		}
  609: 		ndx = rsync_xal_store(sxp->xattr); /* adds item to rsync_xal_l */
  610: 	}
  611: 
  612: 	return ndx;
  613: }
  614: 
  615: /* Return a flag indicating if we need to change a file's xattrs.  If
  616:  * "find_all" is specified, also mark any abbreviated xattrs that we
  617:  * need so that send_xattr_request() can tell the sender about them. */
  618: int xattr_diff(struct file_struct *file, stat_x *sxp, int find_all)
  619: {
  620: 	const rsync_xa_list *glst = rsync_xal_l.items;
  621: 	const item_list *lst;
  622: 	rsync_xa *snd_rxa, *rec_rxa;
  623: 	int snd_cnt, rec_cnt;
  624: 	int cmp, same, xattrs_equal = 1;
  625: 
  626: 	if (sxp && XATTR_READY(*sxp)) {
  627: 		rec_rxa = sxp->xattr->items;
  628: 		rec_cnt = sxp->xattr->count;
  629: 	} else {
  630: 		rec_rxa = NULL;
  631: 		rec_cnt = 0;
  632: 	}
  633: 
  634: 	if (F_XATTR(file) >= 0) {
  635: 		glst += F_XATTR(file);
  636: 		lst = &glst->xa_items;
  637: 	} else
  638: 		lst = &empty_xattr;
  639: 
  640: 	snd_rxa = lst->items;
  641: 	snd_cnt = lst->count;
  642: 
  643: 	/* If the count of the sender's xattrs is different from our
  644: 	 * (receiver's) xattrs, the lists are not the same. */
  645: 	if (snd_cnt != rec_cnt) {
  646: 		if (!find_all)
  647: 			return 1;
  648: 		xattrs_equal = 0;
  649: 	}
  650: 
  651: 	while (snd_cnt) {
  652: 		cmp = rec_cnt ? strcmp(snd_rxa->name, rec_rxa->name) : -1;
  653: 		if (cmp > 0)
  654: 			same = 0;
  655: 		else if (snd_rxa->datum_len > MAX_FULL_DATUM) {
  656: 			same = cmp == 0 && snd_rxa->datum_len == rec_rxa->datum_len
  657: 			    && memcmp(snd_rxa->datum + 1, rec_rxa->datum + 1,
  658: 				      MAX_DIGEST_LEN) == 0;
  659: 			/* Flag unrequested items that we need. */
  660: 			if (!same && find_all && snd_rxa->datum[0] == XSTATE_ABBREV)
  661: 				snd_rxa->datum[0] = XSTATE_TODO;
  662: 		} else {
  663: 			same = cmp == 0 && snd_rxa->datum_len == rec_rxa->datum_len
  664: 			    && memcmp(snd_rxa->datum, rec_rxa->datum,
  665: 				      snd_rxa->datum_len) == 0;
  666: 		}
  667: 		if (!same) {
  668: 			if (!find_all)
  669: 				return 1;
  670: 			xattrs_equal = 0;
  671: 		}
  672: 
  673: 		if (cmp <= 0) {
  674: 			snd_rxa++;
  675: 			snd_cnt--;
  676: 		}
  677: 		if (cmp >= 0) {
  678: 			rec_rxa++;
  679: 			rec_cnt--;
  680: 		}
  681: 	}
  682: 
  683: 	if (rec_cnt)
  684: 		xattrs_equal = 0;
  685: 
  686: 	return !xattrs_equal;
  687: }
  688: 
  689: /* When called by the generator (with a NULL fname), this tells the sender
  690:  * all the abbreviated xattr values we need.  When called by the sender
  691:  * (with a non-NULL fname), we send all the extra xattr data it needs.
  692:  * The generator may also call with f_out < 0 to just change all the
  693:  * XSTATE_ABBREV states into XSTATE_DONE. */
  694: void send_xattr_request(const char *fname, struct file_struct *file, int f_out)
  695: {
  696: 	const rsync_xa_list *glst = rsync_xal_l.items;
  697: 	const item_list *lst;
  698: 	int cnt, prior_req = 0;
  699: 	rsync_xa *rxa;
  700: 
  701: 	glst += F_XATTR(file);
  702: 	lst = &glst->xa_items;
  703: 
  704: 	for (rxa = lst->items, cnt = lst->count; cnt--; rxa++) {
  705: 		if (rxa->datum_len <= MAX_FULL_DATUM)
  706: 			continue;
  707: 		switch (rxa->datum[0]) {
  708: 		case XSTATE_ABBREV:
  709: 			/* Items left abbreviated matched the sender's checksum, so
  710: 			 * the receiver will cache the local data for future use. */
  711: 			if (am_generator)
  712: 				rxa->datum[0] = XSTATE_DONE;
  713: 			continue;
  714: 		case XSTATE_TODO:
  715: 			assert(f_out >= 0);
  716: 			break;
  717: 		default:
  718: 			continue;
  719: 		}
  720: 
  721: 		/* Flag that we handled this abbreviated item. */
  722: 		rxa->datum[0] = XSTATE_DONE;
  723: 
  724: 		write_varint(f_out, rxa->num - prior_req);
  725: 		prior_req = rxa->num;
  726: 
  727: 		if (fname) {
  728: 			size_t len = 0;
  729: 			char *ptr;
  730: 
  731: 			/* Re-read the long datum. */
  732: 			if (!(ptr = get_xattr_data(fname, rxa->name, &len, 0))) {
  733: 				if (errno != ENOTSUP && errno != ENOATTR)
  734: 					rprintf(FERROR_XFER, "failed to re-read xattr %s for %s\n", rxa->name, fname);
  735: 				write_varint(f_out, 0);
  736: 				continue;
  737: 			}
  738: 
  739: 			assert(ptr != UNREAD_DATA);
  740: 			write_varint(f_out, len); /* length might have changed! */
  741: 			write_bigbuf(f_out, ptr, len);
  742: 			free(ptr);
  743: 		}
  744: 	}
  745: 
  746: 	if (f_out >= 0)
  747: 		write_byte(f_out, 0); /* end the list */
  748: }
  749: 
  750: /* When called by the sender, read the request from the generator and mark
  751:  * any needed xattrs with a flag that lets us know they need to be sent to
  752:  * the receiver.  When called by the receiver, reads the sent data and
  753:  * stores it in place of its checksum. */
  754: int recv_xattr_request(struct file_struct *file, int f_in)
  755: {
  756: 	const rsync_xa_list *glst = rsync_xal_l.items;
  757: 	const item_list *lst;
  758: 	char *old_datum, *name;
  759: 	rsync_xa *rxa;
  760: 	int rel_pos, cnt, num, got_xattr_data = 0;
  761: 
  762: 	if (F_XATTR(file) < 0) {
  763: 		rprintf(FERROR, "recv_xattr_request: internal data error!\n");
  764: 		exit_cleanup(RERR_PROTOCOL);
  765: 	}
  766: 	glst += F_XATTR(file);
  767: 	lst = &glst->xa_items;
  768: 
  769: 	cnt = lst->count;
  770: 	rxa = lst->items;
  771: 	num = 0;
  772: 	while ((rel_pos = read_varint(f_in)) != 0) {
  773: 		num += rel_pos;
  774: 		if (am_sender) {
  775: 			/* The sender-related num values are only in order on the sender.
  776: 			 * We use that order here to scan forward or backward as needed. */
  777: 			if (rel_pos < 0) {
  778: 				while (cnt < (int)lst->count && rxa->num > num) {
  779: 					rxa--;
  780: 					cnt++;
  781: 				}
  782: 			} else {
  783: 				while (cnt > 1 && rxa->num < num) {
  784: 					rxa++;
  785: 					cnt--;
  786: 				}
  787: 			}
  788: 		} else {
  789: 			int j;
  790: 			/* The receiving side has no known num order, so we just scan
  791: 			 * forward (w/wrap) and hope that the next value is near by. */
  792: 			for (j = lst->count; j > 1 && rxa->num != num; j--) {
  793: 				if (--cnt)
  794: 					rxa++;
  795: 				else {
  796: 					cnt = lst->count;
  797: 					rxa = lst->items;
  798: 				}
  799: 			}
  800: 		}
  801: 		if (!cnt || rxa->num != num) {
  802: 			rprintf(FERROR, "[%s] could not find xattr #%d for %s\n",
  803: 				who_am_i(), num, f_name(file, NULL));
  804: 			exit_cleanup(RERR_PROTOCOL);
  805: 		}
  806: 		if (!XATTR_ABBREV(*rxa) || rxa->datum[0] != XSTATE_ABBREV) {
  807: 			rprintf(FERROR, "[%s] internal abbrev error on %s (%s, len=%ld)!\n",
  808: 				who_am_i(), f_name(file, NULL), rxa->name, (long)rxa->datum_len);
  809: 			exit_cleanup(RERR_PROTOCOL);
  810: 		}
  811: 
  812: 		if (am_sender) {
  813: 			rxa->datum[0] = XSTATE_TODO;
  814: 			continue;
  815: 		}
  816: 
  817: 		old_datum = rxa->datum;
  818: 		rxa->datum_len = read_varint(f_in);
  819: 
  820: 		if (SIZE_MAX - rxa->name_len < rxa->datum_len)
  821: 			overflow_exit("recv_xattr_request");
  822: 		rxa->datum = new_array(char, rxa->datum_len + rxa->name_len);
  823: 		name = rxa->datum + rxa->datum_len;
  824: 		memcpy(name, rxa->name, rxa->name_len);
  825: 		rxa->name = name;
  826: 		free(old_datum);
  827: 		read_buf(f_in, rxa->datum, rxa->datum_len);
  828: 		got_xattr_data = 1;
  829: 	}
  830: 
  831: 	return got_xattr_data;
  832: }
  833: 
  834: /* ------------------------------------------------------------------------- */
  835: 
  836: /* receive and build the rsync_xattr_lists */
  837: void receive_xattr(int f, struct file_struct *file)
  838: {
  839: 	static item_list temp_xattr = EMPTY_ITEM_LIST;
  840: 	int count, num;
  841: #ifdef HAVE_LINUX_XATTRS
  842: 	int need_sort = 0;
  843: #else
  844: 	int need_sort = 1;
  845: #endif
  846: 	int ndx = read_varint(f);
  847: 
  848: 	if (ndx < 0 || (size_t)ndx > rsync_xal_l.count) {
  849: 		rprintf(FERROR, "receive_xattr: xa index %d out of"
  850: 			" range for %s\n", ndx, f_name(file, NULL));
  851: 		exit_cleanup(RERR_STREAMIO);
  852: 	}
  853: 
  854: 	if (ndx != 0) {
  855: 		F_XATTR(file) = ndx - 1;
  856: 		return;
  857: 	}
  858: 
  859: 	if ((count = read_varint(f)) != 0) {
  860: 		(void)EXPAND_ITEM_LIST(&temp_xattr, rsync_xa, count);
  861: 		temp_xattr.count = 0;
  862: 	}
  863: 
  864: 	for (num = 1; num <= count; num++) {
  865: 		char *ptr, *name;
  866: 		rsync_xa *rxa;
  867: 		size_t name_len = read_varint(f);
  868: 		size_t datum_len = read_varint(f);
  869: 		size_t dget_len = datum_len > MAX_FULL_DATUM ? 1 + MAX_DIGEST_LEN : datum_len;
  870: 		size_t extra_len = MIGHT_NEED_RPRE ? RPRE_LEN : 0;
  871: 		if (SIZE_MAX - dget_len < extra_len || SIZE_MAX - dget_len - extra_len < name_len)
  872: 			overflow_exit("receive_xattr");
  873: 		ptr = new_array(char, dget_len + extra_len + name_len);
  874: 		name = ptr + dget_len + extra_len;
  875: 		read_buf(f, name, name_len);
  876: 		if (name_len < 1 || name[name_len-1] != '\0') {
  877: 			rprintf(FERROR, "Invalid xattr name received (missing trailing \\0).\n");
  878: 			exit_cleanup(RERR_FILEIO);
  879: 		}
  880: 		if (dget_len == datum_len)
  881: 			read_buf(f, ptr, dget_len);
  882: 		else {
  883: 			*ptr = XSTATE_ABBREV;
  884: 			read_buf(f, ptr + 1, MAX_DIGEST_LEN);
  885: 		}
  886: 
  887: 		if (saw_xattr_filter) {
  888: 			if (name_is_excluded(name, NAME_IS_XATTR, ALL_FILTERS)) {
  889: 				free(ptr);
  890: 				continue;
  891: 			}
  892: 		}
  893: #ifdef HAVE_LINUX_XATTRS
  894: 		/* Non-root can only save the user namespace. */
  895: 		if (am_root <= 0 && !HAS_PREFIX(name, USER_PREFIX)) {
  896: 			if (!am_root && !saw_xattr_filter) {
  897: 				free(ptr);
  898: 				continue;
  899: 			}
  900: 			name -= RPRE_LEN;
  901: 			name_len += RPRE_LEN;
  902: 			memcpy(name, RSYNC_PREFIX, RPRE_LEN);
  903: 			need_sort = 1;
  904: 		}
  905: #else
  906: 		/* This OS only has a user namespace, so we either
  907: 		 * strip the user prefix, or we put a non-user
  908: 		 * namespace inside our rsync hierarchy. */
  909: 		if (HAS_PREFIX(name, USER_PREFIX)) {
  910: 			name += UPRE_LEN;
  911: 			name_len -= UPRE_LEN;
  912: 		} else if (am_root) {
  913: 			name -= RPRE_LEN;
  914: 			name_len += RPRE_LEN;
  915: 			memcpy(name, RSYNC_PREFIX, RPRE_LEN);
  916: 		} else {
  917: 			free(ptr);
  918: 			continue;
  919: 		}
  920: #endif
  921: 		/* No rsync.%FOO attributes are copied w/o 2 -X options. */
  922: 		if (preserve_xattrs < 2 && name_len > RPRE_LEN
  923: 		 && name[RPRE_LEN] == '%' && HAS_PREFIX(name, RSYNC_PREFIX)) {
  924: 			free(ptr);
  925: 			continue;
  926: 		}
  927: 
  928: 		rxa = EXPAND_ITEM_LIST(&temp_xattr, rsync_xa, 1);
  929: 		rxa->name = name;
  930: 		rxa->datum = ptr;
  931: 		rxa->name_len = name_len;
  932: 		rxa->datum_len = datum_len;
  933: 		rxa->num = num;
  934: 	}
  935: 
  936: 	if (need_sort && count > 1)
  937: 		qsort(temp_xattr.items, count, sizeof (rsync_xa), rsync_xal_compare_names);
  938: 
  939: 	ndx = rsync_xal_store(&temp_xattr); /* adds item to rsync_xal_l */
  940: 
  941: 	F_XATTR(file) = ndx;
  942: }
  943: 
  944: /* Turn the xattr data in stat_x into cached xattr data, setting the index
  945:  * values in the file struct. */
  946: void cache_tmp_xattr(struct file_struct *file, stat_x *sxp)
  947: {
  948: 	int ndx;
  949: 
  950: 	if (!sxp->xattr)
  951: 		return;
  952: 
  953: 	if (prior_xattr_count == (size_t)-1)
  954: 		prior_xattr_count = rsync_xal_l.count;
  955: 	ndx = find_matching_xattr(sxp->xattr);
  956: 	if (ndx < 0)
  957: 		rsync_xal_store(sxp->xattr); /* adds item to rsync_xal_l */
  958: 
  959: 	F_XATTR(file) = ndx;
  960: }
  961: 
  962: void uncache_tmp_xattrs(void)
  963: {
  964: 	if (prior_xattr_count != (size_t)-1) {
  965: 		rsync_xa_list *xa_list_item = rsync_xal_l.items;
  966: 		rsync_xa_list *xa_list_start = xa_list_item + prior_xattr_count;
  967: 		xa_list_item += rsync_xal_l.count;
  968: 		rsync_xal_l.count = prior_xattr_count;
  969: 		while (xa_list_item-- > xa_list_start) {
  970: 			struct ht_int64_node *node;
  971: 			rsync_xa_list_ref *ref;
  972: 
  973: 			rsync_xal_free(&xa_list_item->xa_items);
  974: 
  975: 			if (rsync_xal_h == NULL)
  976: 				continue;
  977: 
  978: 			node = hashtable_find(rsync_xal_h, xa_list_item->key, NULL);
  979: 			if (node == NULL)
  980: 				continue;
  981: 
  982: 			if (node->data == NULL)
  983: 				continue;
  984: 
  985: 			ref = node->data;
  986: 			if (xa_list_item->ndx == ref->ndx) {
  987: 				/* xa_list_item is the first in the list. */
  988: 				node->data = ref->next;
  989: 				free(ref);
  990: 				continue;
  991: 			}
  992: 
  993: 			while (1) {
  994: 				rsync_xa_list_ref *next = ref->next;
  995: 				if (next == NULL)
  996: 					break;
  997: 				if (xa_list_item->ndx == next->ndx) {
  998: 					ref->next = next->next;
  999: 					free(next);
 1000: 					break;
 1001: 				}
 1002: 				ref = next;
 1003: 			}
 1004: 		}
 1005: 		prior_xattr_count = (size_t)-1;
 1006: 	}
 1007: }
 1008: 
 1009: static int rsync_xal_set(const char *fname, item_list *xalp,
 1010: 			 const char *fnamecmp, stat_x *sxp)
 1011: {
 1012: 	rsync_xa *rxas = xalp->items;
 1013: 	ssize_t list_len;
 1014: 	size_t i, len;
 1015: 	char *name, *ptr, sum[MAX_DIGEST_LEN];
 1016: #ifdef HAVE_LINUX_XATTRS
 1017: 	int user_only = am_root <= 0;
 1018: #endif
 1019: 	size_t name_len;
 1020: 	int flags, ret = 0;
 1021: 
 1022: 	/* This puts the current name list into the "namebuf" buffer. */
 1023: 	if ((list_len = get_xattr_names(fname)) < 0)
 1024: 		return -1;
 1025: 
 1026: 	for (i = 0; i < xalp->count; i++) {
 1027: 		name = rxas[i].name;
 1028: 
 1029: 		if (XATTR_ABBREV(rxas[i])) {
 1030: 			int sum_len;
 1031: 			/* See if the fnamecmp version is identical. */
 1032: 			len = name_len = rxas[i].name_len;
 1033: 			flags = GXD_OMIT_COMPRESSED | GXD_NO_MISSING_ERROR;
 1034: 			if (preserve_hfs_compression && sxp->st.st_flags & UF_COMPRESSED)
 1035: 				flags |= GXD_FILE_IS_COMPRESSED;
 1036: 			if ((ptr = get_xattr_data(fnamecmp, name, &len, flags)) == NULL) {
 1037: 			  still_abbrev:
 1038: 				if (am_generator)
 1039: 					continue;
 1040: 				rprintf(FERROR, "Missing abbreviated xattr value, %s, for %s\n",
 1041: 					rxas[i].name, full_fname(fname));
 1042: 				ret = -1;
 1043: 				continue;
 1044: 			}
 1045: 			if (ptr == UNREAD_DATA)
 1046: 				continue; /* XXX Is this right? */
 1047: 			if (len != rxas[i].datum_len) {
 1048: 				free(ptr);
 1049: 				goto still_abbrev;
 1050: 			}
 1051: 
 1052: 			sum_init(-1, checksum_seed);
 1053: 			sum_update(ptr, len);
 1054: 			sum_len = sum_end(sum);
 1055: 			if (memcmp(sum, rxas[i].datum + 1, sum_len) != 0) {
 1056: 				free(ptr);
 1057: 				goto still_abbrev;
 1058: 			}
 1059: 
 1060: 			if (fname == fnamecmp)
 1061: 				; /* Value is already set when identical */
 1062: 			else if (sys_lsetxattr(fname, name, ptr, len) < 0) {
 1063: 				rsyserr(FERROR_XFER, errno,
 1064: 					"rsync_xal_set: lsetxattr(%s,\"%s\") failed",
 1065: 					full_fname(fname), name);
 1066: 				ret = -1;
 1067: 			} else /* make sure caller sets mtime */
 1068: 				sxp->st.st_mtime = (time_t)-1;
 1069: 
 1070: 			if (am_generator) { /* generator items stay abbreviated */
 1071: 				free(ptr);
 1072: 				continue;
 1073: 			}
 1074: 
 1075: 			memcpy(ptr + len, name, name_len);
 1076: 			free(rxas[i].datum);
 1077: 
 1078: 			rxas[i].name = name = ptr + len;
 1079: 			rxas[i].datum = ptr;
 1080: 			continue;
 1081: 		}
 1082: 
 1083: 		if (sys_lsetxattr(fname, name, rxas[i].datum, rxas[i].datum_len) < 0) {
 1084: 			rsyserr(FERROR_XFER, errno,
 1085: 				"rsync_xal_set: lsetxattr(%s,\"%s\") failed",
 1086: 				full_fname(fname), name);
 1087: 			ret = -1;
 1088: 		} else /* make sure caller sets mtime */
 1089: 			sxp->st.st_mtime = (time_t)-1;
 1090: 	}
 1091: 
 1092: 	/* Remove any extraneous names. */
 1093: 	for (name = namebuf; list_len > 0; name += name_len) {
 1094: 		name_len = strlen(name) + 1;
 1095: 		list_len -= name_len;
 1096: 
 1097: 		if (saw_xattr_filter) {
 1098: 			if (name_is_excluded(name, NAME_IS_XATTR, ALL_FILTERS))
 1099: 				continue;
 1100: 		}
 1101: #ifdef HAVE_LINUX_XATTRS
 1102: 		/* Choose between ignoring the system namespace or (non-root) ignoring any non-user namespace. */
 1103: 		else if (user_only ? !HAS_PREFIX(name, USER_PREFIX) : HAS_PREFIX(name, SYSTEM_PREFIX))
 1104: 			continue;
 1105: #endif
 1106: 		if (am_root < 0 && name_len > RPRE_LEN && name[RPRE_LEN] == '%' && strcmp(name, XSTAT_ATTR) == 0)
 1107: 			continue;
 1108: 
 1109: 		for (i = 0; i < xalp->count; i++) {
 1110: 			if (strcmp(name, rxas[i].name) == 0)
 1111: 				break;
 1112: 		}
 1113: 		if (i == xalp->count) {
 1114: 			if (sys_lremovexattr(fname, name) < 0) {
 1115: 				rsyserr(FERROR_XFER, errno,
 1116: 					"rsync_xal_set: lremovexattr(%s,\"%s\") failed",
 1117: 					full_fname(fname), name);
 1118: 				ret = -1;
 1119: 			} else /* make sure caller sets mtime */
 1120: 				sxp->st.st_mtime = (time_t)-1;
 1121: 		}
 1122: 	}
 1123: 
 1124: #ifdef HAVE_OSX_XATTRS
 1125: 	rsync_xal_free(xalp); /* Free this because we aren't using find_matching_xattr(). */
 1126: #endif
 1127: 
 1128: 	return ret;
 1129: }
 1130: 
 1131: /* Set extended attributes on indicated filename. */
 1132: int set_xattr(const char *fname, const struct file_struct *file, const char *fnamecmp, stat_x *sxp)
 1133: {
 1134: 	rsync_xa_list *glst = rsync_xal_l.items;
 1135: 	item_list *lst;
 1136: 	int ndx;
 1137: 
 1138: 	if (dry_run)
 1139: 		return 1; /* FIXME: --dry-run needs to compute this value */
 1140: 
 1141: 	if (read_only || list_only) {
 1142: 		errno = EROFS;
 1143: 		return -1;
 1144: 	}
 1145: 
 1146: #ifdef NO_SPECIAL_XATTRS
 1147: 	if (IS_SPECIAL(sxp->st.st_mode)) {
 1148: 		errno = ENOTSUP;
 1149: 		return -1;
 1150: 	}
 1151: #endif
 1152: #ifdef NO_DEVICE_XATTRS
 1153: 	if (IS_DEVICE(sxp->st.st_mode)) {
 1154: 		errno = ENOTSUP;
 1155: 		return -1;
 1156: 	}
 1157: #endif
 1158: #ifdef NO_SYMLINK_XATTRS
 1159: 	if (S_ISLNK(sxp->st.st_mode)) {
 1160: 		errno = ENOTSUP;
 1161: 		return -1;
 1162: 	}
 1163: #endif
 1164: 
 1165: 	ndx = F_XATTR(file);
 1166: 	glst += ndx;
 1167: 	lst = &glst->xa_items;
 1168: 	return rsync_xal_set(fname, lst, fnamecmp, sxp);
 1169: }
 1170: 
 1171: #ifdef SUPPORT_ACLS
 1172: char *get_xattr_acl(const char *fname, int is_access_acl, size_t *len_p)
 1173: {
 1174: 	const char *name = is_access_acl ? XACC_ACL_ATTR : XDEF_ACL_ATTR;
 1175: 	*len_p = 0; /* no extra data alloc needed from get_xattr_data() */
 1176: 	return get_xattr_data(fname, name, len_p, GXD_NO_MISSING_ERROR);
 1177: }
 1178: 
 1179: int set_xattr_acl(const char *fname, int is_access_acl, const char *buf, size_t buf_len)
 1180: {
 1181: 	const char *name = is_access_acl ? XACC_ACL_ATTR : XDEF_ACL_ATTR;
 1182: 	if (sys_lsetxattr(fname, name, buf, buf_len) < 0) {
 1183: 		rsyserr(FERROR_XFER, errno,
 1184: 			"set_xattr_acl: lsetxattr(%s,\"%s\") failed",
 1185: 			full_fname(fname), name);
 1186: 		return -1;
 1187: 	}
 1188: 	return 0;
 1189: }
 1190: 
 1191: int del_def_xattr_acl(const char *fname)
 1192: {
 1193: 	return sys_lremovexattr(fname, XDEF_ACL_ATTR);
 1194: }
 1195: #endif
 1196: 
 1197: int get_sum_xattr(const char *fname, STRUCT_STAT *stp, char *sum)
 1198: {
 1199: 	const char *mdattr = checksum_type == 5 ? MD5_ATTR : MD4_ATTR;
 1200: 	char buf[256];
 1201: 	uint32 file_length, mtime;
 1202: 	int len;
 1203: 
 1204: 	len = sys_lgetxattr(fname, mdattr, buf, sizeof buf);
 1205: 	if (len < 0) {
 1206: 		if (errno == ENOTSUP || errno == ENOATTR)
 1207: 			return 0;
 1208: 		rsyserr(FERROR_XFER, errno, "failed to read xattr %s for %s",
 1209: 			mdattr, full_fname(fname));
 1210: 		return 0;
 1211: 	}
 1212: 	if (len != 4 + 4 + flist_csum_len) {
 1213: 		rprintf(FERROR, "Corrupt %s xattr attached to %s -- skipping\n",
 1214: 			mdattr, full_fname(fname));
 1215: 		return 0;
 1216: 	}
 1217: 
 1218: 	file_length = IVAL(buf, 0); /* 32-bit values -- trunctions are OK */
 1219: 	mtime = IVAL(buf, 4);
 1220: 
 1221: 	if ((uint32)stp->st_size != file_length || (uint32)stp->st_mtime != mtime)
 1222: 		return 0;
 1223: 
 1224: 	memcpy(sum, buf + 8, flist_csum_len);
 1225: 
 1226: 	return 1;
 1227: }
 1228: 
 1229: int get_stat_xattr(const char *fname, int fd, STRUCT_STAT *fst, STRUCT_STAT *xst)
 1230: {
 1231: 	int mode, rdev_major, rdev_minor, uid, gid, len;
 1232: 	char buf[256];
 1233: 
 1234: 	if (am_root >= 0 || IS_DEVICE(fst->st_mode) || IS_SPECIAL(fst->st_mode))
 1235: 		return -1;
 1236: 
 1237: 	if (xst)
 1238: 		*xst = *fst;
 1239: 	else
 1240: 		xst = fst;
 1241: 	if (fname) {
 1242: 		fd = -1;
 1243: 		len = sys_lgetxattr(fname, XSTAT_ATTR, buf, sizeof buf - 1);
 1244: 	} else {
 1245: 		fname = "fd";
 1246: 		len = sys_fgetxattr(fd, XSTAT_ATTR, buf, sizeof buf - 1);
 1247: 	}
 1248: 	if (len >= (int)sizeof buf) {
 1249: 		len = -1;
 1250: 		errno = ERANGE;
 1251: 	}
 1252: 	if (len < 0) {
 1253: 		if (errno == ENOTSUP || errno == ENOATTR)
 1254: 			return -1;
 1255: 		if (errno == EPERM && S_ISLNK(fst->st_mode)) {
 1256: 			xst->st_uid = 0;
 1257: 			xst->st_gid = 0;
 1258: 			return 0;
 1259: 		}
 1260: 		rsyserr(FERROR_XFER, errno, "failed to read xattr %s for %s",
 1261: 			XSTAT_ATTR, full_fname(fname));
 1262: 		return -1;
 1263: 	}
 1264: 	buf[len] = '\0';
 1265: 
 1266: 	if (sscanf(buf, "%o %d,%d %d:%d",
 1267: 		   &mode, &rdev_major, &rdev_minor, &uid, &gid) != 5) {
 1268: 		rprintf(FERROR, "Corrupt %s xattr attached to %s: \"%s\"\n",
 1269: 			XSTAT_ATTR, full_fname(fname), buf);
 1270: 		exit_cleanup(RERR_FILEIO);
 1271: 	}
 1272: 
 1273: 	xst->st_mode = from_wire_mode(mode);
 1274: 	xst->st_rdev = MAKEDEV(rdev_major, rdev_minor);
 1275: 	xst->st_uid = uid;
 1276: 	xst->st_gid = gid;
 1277: 
 1278: 	return 0;
 1279: }
 1280: 
 1281: int set_stat_xattr(const char *fname, struct file_struct *file, mode_t new_mode)
 1282: {
 1283: 	STRUCT_STAT fst, xst;
 1284: 	dev_t rdev;
 1285: 	mode_t mode, fmode;
 1286: 
 1287: 	if (dry_run)
 1288: 		return 0;
 1289: 
 1290: 	if (read_only || list_only) {
 1291: 		rsyserr(FERROR_XFER, EROFS, "failed to write xattr %s for %s",
 1292: 			XSTAT_ATTR, full_fname(fname));
 1293: 		return -1;
 1294: 	}
 1295: 
 1296: 	if (x_lstat(fname, &fst, &xst) < 0) {
 1297: 		rsyserr(FERROR_XFER, errno, "failed to re-stat %s",
 1298: 			full_fname(fname));
 1299: 		return -1;
 1300: 	}
 1301: 
 1302: 	fst.st_mode &= (_S_IFMT | CHMOD_BITS);
 1303: 	fmode = new_mode & (_S_IFMT | CHMOD_BITS);
 1304: 
 1305: 	if (IS_DEVICE(fmode)) {
 1306: 		uint32 *devp = F_RDEV_P(file);
 1307: 		rdev = MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp));
 1308: 	} else
 1309: 		rdev = 0;
 1310: 
 1311: 	/* Dump the special permissions and enable full owner access. */
 1312: 	mode = (fst.st_mode & _S_IFMT) | (fmode & ACCESSPERMS)
 1313: 	     | (S_ISDIR(fst.st_mode) ? 0700 : 0600);
 1314: 	if (fst.st_mode != mode)
 1315: 		do_chmod(fname, mode, ST_FLAGS(fst));
 1316: 	if (!IS_DEVICE(fst.st_mode))
 1317: 		fst.st_rdev = 0; /* just in case */
 1318: 
 1319: 	if (mode == fmode && fst.st_rdev == rdev
 1320: 	 && fst.st_uid == F_OWNER(file) && fst.st_gid == F_GROUP(file)) {
 1321: 		/* xst.st_mode will be 0 if there's no current stat xattr */
 1322: 		if (xst.st_mode && sys_lremovexattr(fname, XSTAT_ATTR) < 0) {
 1323: 			rsyserr(FERROR_XFER, errno,
 1324: 				"delete of stat xattr failed for %s",
 1325: 				full_fname(fname));
 1326: 			return -1;
 1327: 		}
 1328: 		return 0;
 1329: 	}
 1330: 
 1331: 	if (xst.st_mode != fmode || xst.st_rdev != rdev
 1332: 	 || xst.st_uid != F_OWNER(file) || xst.st_gid != F_GROUP(file)) {
 1333: 		char buf[256];
 1334: 		int len = snprintf(buf, sizeof buf, "%o %u,%u %u:%u",
 1335: 			to_wire_mode(fmode),
 1336: 			(int)major(rdev), (int)minor(rdev),
 1337: 			F_OWNER(file), F_GROUP(file));
 1338: 		if (sys_lsetxattr(fname, XSTAT_ATTR, buf, len) < 0) {
 1339: 			if (errno == EPERM && S_ISLNK(fst.st_mode))
 1340: 				return 0;
 1341: 			rsyserr(FERROR_XFER, errno,
 1342: 				"failed to write xattr %s for %s",
 1343: 				XSTAT_ATTR, full_fname(fname));
 1344: 			return -1;
 1345: 		}
 1346: 	}
 1347: 
 1348: 	return 0;
 1349: }
 1350: 
 1351: #ifdef SUPPORT_HFS_COMPRESSION
 1352: static inline void hfs_compress_tweaks(STRUCT_STAT *fst)
 1353: {
 1354: 	if (fst->st_flags & UF_COMPRESSED) {
 1355: 		if (preserve_hfs_compression) {
 1356: 			/* We're sending the compression xattr, not the decompressed data fork.
 1357: 			 * Setting rsync's idea of the file size to 0 effectively prevents the
 1358: 			 * transfer of the data fork. */
 1359: 			fst->st_size = 0;
 1360: 		} else {
 1361: 			/* If the sender's filesystem supports compression, then we'll be able
 1362: 			 * to send the decompressed data fork and the decmpfs xattr will be
 1363: 			 * hidden (not sent). As such, we need to strip the compression flag. */
 1364: 			fst->st_flags &= ~UF_COMPRESSED;
 1365: 		}
 1366: 	}
 1367: }
 1368: #endif
 1369: 
 1370: int x_stat(const char *fname, STRUCT_STAT *fst, STRUCT_STAT *xst)
 1371: {
 1372: 	int ret = do_stat(fname, fst);
 1373: 	if ((ret < 0 || get_stat_xattr(fname, -1, fst, xst) < 0) && xst)
 1374: 		xst->st_mode = 0;
 1375: #ifdef SUPPORT_HFS_COMPRESSION
 1376: 	hfs_compress_tweaks(fst);
 1377: #endif
 1378: 	return ret;
 1379: }
 1380: 
 1381: int x_lstat(const char *fname, STRUCT_STAT *fst, STRUCT_STAT *xst)
 1382: {
 1383: 	int ret = do_lstat(fname, fst);
 1384: 	if ((ret < 0 || get_stat_xattr(fname, -1, fst, xst) < 0) && xst)
 1385: 		xst->st_mode = 0;
 1386: #ifdef SUPPORT_HFS_COMPRESSION
 1387: 	hfs_compress_tweaks(fst);
 1388: #endif
 1389: 	return ret;
 1390: }
 1391: 
 1392: int x_fstat(int fd, STRUCT_STAT *fst, STRUCT_STAT *xst)
 1393: {
 1394: 	int ret = do_fstat(fd, fst);
 1395: 	if ((ret < 0 || get_stat_xattr(NULL, fd, fst, xst) < 0) && xst)
 1396: 		xst->st_mode = 0;
 1397: #ifdef SUPPORT_HFS_COMPRESSION
 1398: 	hfs_compress_tweaks(fst);
 1399: #endif
 1400: 	return ret;
 1401: }
 1402: 
 1403: #endif /* SUPPORT_XATTRS */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>