File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / lib / sysxattrs.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Nov 1 09:54:32 2016 UTC (7 years, 8 months ago) by misho
Branches: rsync, MAIN
CVS tags: v3_1_2p5, HEAD
rsync 3.1.2

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

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