File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / lib / sysxattrs.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, 4 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:  *
    4:  * Copyright (C) 2004 Red Hat, Inc.
    5:  * Copyright (C) 2003-2019 Wayne Davison
    6:  * Written by Jay Fenlason.
    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 "sysxattrs.h"
   24: 
   25: extern int preserve_hfs_compression;
   26: 
   27: #ifdef SUPPORT_XATTRS
   28: 
   29: #ifdef HAVE_OSX_XATTRS
   30: #ifndef XATTR_SHOWCOMPRESSION
   31: #define XATTR_SHOWCOMPRESSION 0x0020
   32: #endif
   33: #define GETXATTR_FETCH_LIMIT (64*1024*1024)
   34: 
   35: int xattr_options = XATTR_NOFOLLOW;
   36: #endif
   37: 
   38: #if defined HAVE_LINUX_XATTRS
   39: 
   40: ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size)
   41: {
   42: 	return lgetxattr(path, name, value, size);
   43: }
   44: 
   45: ssize_t sys_fgetxattr(int filedes, const char *name, void *value, size_t size)
   46: {
   47: 	return fgetxattr(filedes, name, value, size);
   48: }
   49: 
   50: int sys_lsetxattr(const char *path, const char *name, const void *value, size_t size)
   51: {
   52: 	return lsetxattr(path, name, value, size, 0);
   53: }
   54: 
   55: int sys_lremovexattr(const char *path, const char *name)
   56: {
   57: 	return lremovexattr(path, name);
   58: }
   59: 
   60: ssize_t sys_llistxattr(const char *path, char *list, size_t size)
   61: {
   62: 	return llistxattr(path, list, size);
   63: }
   64: 
   65: #elif HAVE_OSX_XATTRS
   66: 
   67: ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size)
   68: {
   69: 	ssize_t len;
   70: 
   71: 	if (preserve_hfs_compression)
   72: 		xattr_options |= XATTR_SHOWCOMPRESSION;
   73: 
   74: 	len = getxattr(path, name, value, size, 0, xattr_options);
   75: 
   76: 	/* If we're retrieving data, handle resource forks > 64MB specially */
   77: 	if (value != NULL && len == GETXATTR_FETCH_LIMIT && (size_t)len < size) {
   78: 		/* getxattr will only return 64MB of data at a time, need to call again with a new offset */
   79: 		u_int32_t offset = len;
   80: 		size_t data_retrieved = len;
   81: 		while (data_retrieved < size) {
   82: 			len = getxattr(path, name, value + offset, size - data_retrieved, offset, xattr_options);
   83: 			if (len <= 0)
   84: 				break;
   85: 			data_retrieved += len;
   86: 			offset += (u_int32_t)len;
   87: 		}
   88: 		len = data_retrieved;
   89: 	}
   90: 
   91: 	return len;
   92: }
   93: 
   94: ssize_t sys_fgetxattr(int filedes, const char *name, void *value, size_t size)
   95: {
   96: 	return fgetxattr(filedes, name, value, size, 0, 0);
   97: }
   98: 
   99: int sys_lsetxattr(const char *path, const char *name, const void *value, size_t size)
  100: {
  101: 	return setxattr(path, name, value, size, 0, XATTR_NOFOLLOW);
  102: }
  103: 
  104: int sys_lremovexattr(const char *path, const char *name)
  105: {
  106: 	if (preserve_hfs_compression)
  107: 		xattr_options |= XATTR_SHOWCOMPRESSION;
  108: 	return removexattr(path, name, xattr_options);
  109: }
  110: 
  111: ssize_t sys_llistxattr(const char *path, char *list, size_t size)
  112: {
  113: 	if (preserve_hfs_compression)
  114: 		xattr_options |= XATTR_SHOWCOMPRESSION;
  115: 	return listxattr(path, list, size, xattr_options);
  116: }
  117: 
  118: #elif HAVE_FREEBSD_XATTRS
  119: 
  120: ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size)
  121: {
  122: 	return extattr_get_link(path, EXTATTR_NAMESPACE_USER, name, value, size);
  123: }
  124: 
  125: ssize_t sys_fgetxattr(int filedes, const char *name, void *value, size_t size)
  126: {
  127: 	return extattr_get_fd(filedes, EXTATTR_NAMESPACE_USER, name, value, size);
  128: }
  129: 
  130: int sys_lsetxattr(const char *path, const char *name, const void *value, size_t size)
  131: {
  132: 	return extattr_set_link(path, EXTATTR_NAMESPACE_USER, name, value, size);
  133: }
  134: 
  135: int sys_lremovexattr(const char *path, const char *name)
  136: {
  137: 	return extattr_delete_link(path, EXTATTR_NAMESPACE_USER, name);
  138: }
  139: 
  140: ssize_t sys_llistxattr(const char *path, char *list, size_t size)
  141: {
  142: 	unsigned char keylen;
  143: 	ssize_t off, len = extattr_list_link(path, EXTATTR_NAMESPACE_USER, list, size);
  144: 
  145: 	if (len <= 0 || (size_t)len > size)
  146: 		return len;
  147: 
  148: 	/* FreeBSD puts a single-byte length before each string, with no '\0'
  149: 	 * terminator.  We need to change this into a series of null-terminted
  150: 	 * strings.  Since the size is the same, we can simply transform the
  151: 	 * output in place. */
  152: 	for (off = 0; off < len; off += keylen + 1) {
  153: 		keylen = ((unsigned char*)list)[off];
  154: 		if (off + keylen >= len) {
  155: 			/* Should be impossible, but kernel bugs happen! */
  156: 			errno = EINVAL;
  157: 			return -1;
  158: 		}
  159: 		memmove(list+off, list+off+1, keylen);
  160: 		list[off+keylen] = '\0';
  161: 	}
  162: 
  163: 	return len;
  164: }
  165: 
  166: #elif HAVE_SOLARIS_XATTRS
  167: 
  168: static ssize_t read_xattr(int attrfd, void *buf, size_t buflen)
  169: {
  170: 	STRUCT_STAT sb;
  171: 	ssize_t ret;
  172: 
  173: 	if (fstat(attrfd, &sb) < 0)
  174: 		ret = -1;
  175: 	else if (sb.st_size > SSIZE_MAX) {
  176: 		errno = ERANGE;
  177: 		ret = -1;
  178: 	} else if (buflen == 0)
  179: 		ret = sb.st_size;
  180: 	else if (sb.st_size > buflen) {
  181: 		errno = ERANGE;
  182: 		ret = -1;
  183: 	} else {
  184: 		size_t bufpos;
  185: 		for (bufpos = 0; bufpos < sb.st_size; ) {
  186: 			ssize_t cnt = read(attrfd, buf + bufpos, sb.st_size - bufpos);
  187: 			if (cnt <= 0) {
  188: 				if (cnt < 0 && errno == EINTR)
  189: 					continue;
  190: 				bufpos = -1;
  191: 				break;
  192: 			}
  193: 			bufpos += cnt;
  194: 		}
  195: 		ret = bufpos;
  196: 	}
  197: 
  198: 	close(attrfd);
  199: 
  200: 	return ret;
  201: }
  202: 
  203: ssize_t sys_lgetxattr(const char *path, const char *name, void *value, size_t size)
  204: {
  205: 	int attrfd;
  206: 
  207: 	if ((attrfd = attropen(path, name, O_RDONLY)) < 0) {
  208: 		errno = ENOATTR;
  209: 		return -1;
  210: 	}
  211: 
  212: 	return read_xattr(attrfd, value, size);
  213: }
  214: 
  215: ssize_t sys_fgetxattr(int filedes, const char *name, void *value, size_t size)
  216: {
  217: 	int attrfd;
  218: 
  219: 	if ((attrfd = openat(filedes, name, O_RDONLY|O_XATTR, 0)) < 0) {
  220: 		errno = ENOATTR;
  221: 		return -1;
  222: 	}
  223: 
  224: 	return read_xattr(attrfd, value, size);
  225: }
  226: 
  227: int sys_lsetxattr(const char *path, const char *name, const void *value, size_t size)
  228: {
  229: 	int attrfd;
  230: 	size_t bufpos;
  231: 	mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
  232: 
  233: 	if ((attrfd = attropen(path, name, O_CREAT|O_TRUNC|O_WRONLY, mode)) < 0)
  234: 		return -1;
  235: 
  236: 	for (bufpos = 0; bufpos < size; ) {
  237: 		ssize_t cnt = write(attrfd, value+bufpos, size);
  238: 		if (cnt <= 0) {
  239: 			if (cnt < 0 && errno == EINTR)
  240: 				continue;
  241: 			bufpos = -1;
  242: 			break;
  243: 		}
  244: 		bufpos += cnt;
  245: 	}
  246: 
  247: 	close(attrfd);
  248: 
  249: 	return bufpos > 0 ? 0 : -1;
  250: }
  251: 
  252: int sys_lremovexattr(const char *path, const char *name)
  253: {
  254: 	int attrdirfd;
  255: 	int ret;
  256: 
  257: 	if ((attrdirfd = attropen(path, ".", O_RDONLY)) < 0)
  258: 		return -1;
  259: 
  260: 	ret = unlinkat(attrdirfd, name, 0);
  261: 
  262: 	close(attrdirfd);
  263: 
  264: 	return ret;
  265: }
  266: 
  267: ssize_t sys_llistxattr(const char *path, char *list, size_t size)
  268: {
  269: 	int attrdirfd;
  270: 	DIR *dirp;
  271: 	struct dirent *dp;
  272: 	ssize_t ret = 0;
  273: 
  274: 	if ((attrdirfd = attropen(path, ".", O_RDONLY)) < 0) {
  275: 		errno = ENOTSUP;
  276: 		return -1;
  277: 	}
  278: 
  279: 	if ((dirp = fdopendir(attrdirfd)) == NULL) {
  280: 		close(attrdirfd);
  281: 		return -1;
  282: 	}
  283: 
  284: 	while ((dp = readdir(dirp))) {
  285: 		int len = strlen(dp->d_name);
  286: 
  287: 		if (dp->d_name[0] == '.' && (len == 1 || (len == 2 && dp->d_name[1] == '.')))
  288: 			continue;
  289: 		if (len == 11 && dp->d_name[0] == 'S' && strncmp(dp->d_name, "SUNWattr_r", 10) == 0
  290: 		 && (dp->d_name[10] == 'o' || dp->d_name[10] == 'w'))
  291: 			continue;
  292: 
  293: 		if ((ret += len+1) > size) {
  294: 			if (size == 0)
  295: 				continue;
  296: 			ret = -1;
  297: 			errno = ERANGE;
  298: 			break;
  299: 		}
  300: 		memcpy(list, dp->d_name, len+1);
  301: 		list += len+1;
  302: 	}
  303: 
  304: 	closedir(dirp);
  305: 	close(attrdirfd);
  306: 
  307: 	return ret;
  308: }
  309: 
  310: #else
  311: 
  312: #error You need to create xattr compatibility functions.
  313: 
  314: #endif
  315: 
  316: #endif /* SUPPORT_XATTRS */

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