OpenSolaris_b135/lib/libcmdutils/common/process_xattrs.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include "libcmdutils.h"


/*
 * Gets file descriptors of attribute directories for source and target
 * attribute files
 */
int
get_attrdirs(int indfd, int outdfd, char *attrfile, int *sfd, int *tfd)
{
	int	pwdfd;
	int	fd1;
	int	fd2;

	pwdfd = open(".", O_RDONLY);
	if ((pwdfd != -1) && (fchdir(indfd) == 0)) {
		if ((fd1 = attropen(attrfile, ".", O_RDONLY)) == -1) {
			(void) fchdir(pwdfd);
			(void) close(pwdfd);
			return (1);
		}
		*sfd = fd1;
	} else {
		(void) fchdir(pwdfd);
		(void) close(pwdfd);
		return (1);
	}
	if (fchdir(outdfd) == 0) {
		if ((fd2 = attropen(attrfile, ".", O_RDONLY)) == -1) {
			(void) fchdir(pwdfd);
			(void) close(pwdfd);
			return (1);
		}
		*tfd = fd2;
	} else {
		(void) fchdir(pwdfd);
		(void) close(pwdfd);
		return (1);
	}
	(void) fchdir(pwdfd);
	return (0);
}

/*
 * mv_xattrs - Copies the content of the extended attribute files. Then
 * 	moves the extended system attributes from the input attribute files
 *      to the target attribute files. Moves the extended system attributes
 *	from source to the target file. This function returns 0 on success
 *	and nonzero on error.
 */
int
mv_xattrs(char *cmd, char *infile, char *outfile, int sattr, int silent)
{
	int srcfd = -1;
	int indfd = -1;
	int outdfd = -1;
	int tmpfd = -1;
	int sattrfd = -1;
	int tattrfd = -1;
	int asfd = -1;
	int atfd = -1;
	DIR *dirp = NULL;
	struct dirent *dp = NULL;
	char *etext = NULL;
	struct stat st1;
	struct stat st2;
	nvlist_t *response = NULL;
	nvlist_t *res = NULL;

	if ((srcfd = open(infile, O_RDONLY)) == -1) {
		etext = dgettext(TEXT_DOMAIN, "cannot open source");
		goto error;
	}
	if (sattr)
		response = sysattr_list(cmd, srcfd, infile);

	if ((indfd = openat(srcfd, ".", O_RDONLY|O_XATTR)) == -1) {
		etext = dgettext(TEXT_DOMAIN, "cannot openat source");
		goto error;
	}
	if ((outdfd = attropen(outfile, ".", O_RDONLY)) == -1) {
		etext = dgettext(TEXT_DOMAIN, "cannot attropen target");
		goto error;
	}
	if ((tmpfd = dup(indfd)) == -1) {
		etext = dgettext(TEXT_DOMAIN, "cannot dup descriptor");
		goto error;

	}
	if ((dirp = fdopendir(tmpfd)) == NULL) {
		etext = dgettext(TEXT_DOMAIN, "cannot access source");
		goto error;
	}
	while ((dp = readdir(dirp)) != NULL) {
		if ((dp->d_name[0] == '.' && dp->d_name[1] == '\0') ||
		    (dp->d_name[0] == '.' && dp->d_name[1] == '.' &&
		    dp->d_name[2] == '\0') ||
		    (sysattr_type(dp->d_name) == _RO_SATTR) ||
		    (sysattr_type(dp->d_name) == _RW_SATTR))
			continue;

		if ((sattrfd = openat(indfd, dp->d_name,
		    O_RDONLY)) == -1) {
			etext = dgettext(TEXT_DOMAIN,
			    "cannot open src attribute file");
			goto error;
		}
		if (fstat(sattrfd, &st1) < 0) {
			etext = dgettext(TEXT_DOMAIN,
			    "could not stat attribute file");
			goto error;
		}
		if ((tattrfd = openat(outdfd, dp->d_name,
		    O_RDWR|O_CREAT|O_TRUNC, st1.st_mode)) == -1) {
			etext = dgettext(TEXT_DOMAIN,
			    "cannot open target attribute file");
			goto error;
		}
		if (fstat(tattrfd, &st2) < 0) {
			etext = dgettext(TEXT_DOMAIN,
			    "could not stat attribute file");
			goto error;
		}
		if (writefile(sattrfd, tattrfd, infile, outfile, dp->d_name,
		    dp->d_name, &st1, &st2) != 0) {
			etext = dgettext(TEXT_DOMAIN,
			    "failed to copy extended attribute "
			    "from source to target");
			goto error;
		}

		errno = 0;
		if (sattr) {
			/*
			 * Gets non default extended system attributes from
			 * source to copy to target.
			 */
			if (dp->d_name != NULL)
				res = sysattr_list(cmd, sattrfd, dp->d_name);

			if (res != NULL &&
			    get_attrdirs(indfd, outdfd, dp->d_name, &asfd,
			    &atfd) != 0) {
				etext = dgettext(TEXT_DOMAIN,
				    "Failed to open attribute files");
				goto error;
			}
			/*
			 * Copy extended system attribute from source
			 * attribute file to target attribute file
			 */
			if (res != NULL &&
			    (renameat(asfd, VIEW_READWRITE, atfd,
			    VIEW_READWRITE) != 0)) {
				if (errno == EPERM)
					etext = dgettext(TEXT_DOMAIN,
					    "Permission denied -"
					    "failed to move system attribute");
				else
					etext = dgettext(TEXT_DOMAIN,
					    "failed to move extended "
					    "system attribute");
				goto error;
			}
		}
		if (sattrfd != -1)
			(void) close(sattrfd);
		if (tattrfd != -1)
			(void) close(tattrfd);
		if (asfd != -1)
			(void) close(asfd);
		if (atfd != -1)
			(void) close(atfd);
		if (res != NULL) {
			nvlist_free(res);
			res = NULL;
		}
	}
	errno = 0;
	/* Copy extended system attribute from source to target */

	if (response != NULL) {
		if (renameat(indfd, VIEW_READWRITE, outdfd,
		    VIEW_READWRITE) == 0)
			goto done;

		if (errno == EPERM)
			etext = dgettext(TEXT_DOMAIN, "Permission denied");
		else
			etext = dgettext(TEXT_DOMAIN,
			    "failed to move system attribute");
	}
error:
	if (res != NULL)
		nvlist_free(res);
	if (silent == 0 && etext != NULL) {
		if (!sattr)
			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
			    "%s: %s: cannot move extended attributes, "),
			    cmd, infile);
		else
			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
			    "%s: %s: cannot move extended system "
			    "attributes, "), cmd, infile);
		perror(etext);
	}
done:
	if (dirp)
		(void) closedir(dirp);
	if (sattrfd != -1)
		(void) close(sattrfd);
	if (tattrfd != -1)
		(void) close(tattrfd);
	if (asfd != -1)
		(void) close(asfd);
	if (atfd != -1)
		(void) close(atfd);
	if (indfd != -1)
		(void) close(indfd);
	if (outdfd != -1)
		(void) close(outdfd);
	if (response != NULL)
		nvlist_free(response);
	if (etext != NULL)
		return (1);
	else
		return (0);
}

/*
 * The function returns non default extended system attribute list
 * associated with 'fname' and returns NULL when an error has occured
 * or when only extended system attributes other than archive,
 * av_modified or crtime are set.
 *
 * The function returns system attribute list for the following cases:
 *
 *	- any extended system attribute other than the default attributes
 *	  ('archive', 'av_modified' and 'crtime') is set
 *	- nvlist has NULL name string
 *	- nvpair has data type of 'nvlist'
 *	- default data type.
 */

nvlist_t *
sysattr_list(char *cmd, int fd, char *fname)
{
	boolean_t	value;
	data_type_t	type;
	nvlist_t	*response;
	nvpair_t	*pair;
	f_attr_t	fattr;
	char		*name;

	if (fgetattr(fd, XATTR_VIEW_READWRITE, &response) != 0) {
		(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
		    "%s: %s: fgetattr failed\n"),
		    cmd, fname);
		return (NULL);
	}
	pair = NULL;
	while ((pair = nvlist_next_nvpair(response, pair)) != NULL) {

		name = nvpair_name(pair);

		if (name != NULL)
			fattr = name_to_attr(name);
		else
			return (response);

		type = nvpair_type(pair);
		switch (type) {
			case DATA_TYPE_BOOLEAN_VALUE:
				if (nvpair_value_boolean_value(pair,
				    &value) != 0) {
					(void) fprintf(stderr,
					    dgettext(TEXT_DOMAIN, "%s "
					    "nvpair_value_boolean_value "
					    "failed\n"), cmd);
					continue;
				}
				if (value && fattr != F_ARCHIVE &&
				    fattr != F_AV_MODIFIED)
					return (response);
				break;
			case DATA_TYPE_UINT64_ARRAY:
				if (fattr != F_CRTIME)
					return (response);
				break;
			case DATA_TYPE_NVLIST:
			default:
				return (response);
				break;
		}
	}
	if (response != NULL)
		nvlist_free(response);
	return (NULL);
}