OpenSolaris_b135/lib/libsec/common/aclsort.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, Version 1.0 only
 * (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 (c) 1993-1997 by Sun Microsystems, Inc.
 * All rights reserved
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"
/*LINTLIBRARY*/

/*
 * aclsort():
 *	Sort an ACL by entry type according to the following order:
 *	USER_OBJ, USER, GROUP_OBJ, GROUP, CLASS_OBJ, OTHER_OBJ
 *	DEF_USER_OBJ, DEF_USER, DEF_GROUP_OBJ, DEF_GROUP, DEF_CLASS_OBJ,
 *	DEF_OTHER_OBJ.
 *	For USER, GROUP, DEF_USER, and DEF_GROUP entries, the entries
 *	are further sorted by ids.
 */

#include <stdlib.h>
#include <sys/acl.h>

#define	TOTAL_ENTRY_TYPES	12

/*
 * This maps the entry defined value to a value for sorting.
 * These values may not be the same. It is easier to add an
 * entry type with this map.
 *
 * Because the defines and sorting order are not the same,
 * the following map_to_sort table is needed.
 */
struct map {
	int	sort_order;
	int	entry_type;
};

static struct map map_to_sort[] = {
		{0, 0}, /* UNUSED */
		{1,	USER_OBJ},
		{2,	USER},
		{3, 	GROUP_OBJ},
		{4,	GROUP},
		{5,	CLASS_OBJ},
		{6, 	OTHER_OBJ},
		{7, 	DEF_USER_OBJ},
		{8, 	DEF_USER},
		{9, 	DEF_GROUP_OBJ},
		{10,	DEF_GROUP},
		{11,	DEF_CLASS_OBJ},
		{12,	DEF_OTHER_OBJ},
};

static int entrycmp(const aclent_t *, const aclent_t *);
static int idcmp(const aclent_t *, const aclent_t *);
static void sortid(aclent_t *, int, int);

int
aclsort(int nentries, int calcmask, aclent_t *aclbufp)
{
	aclent_t		*tp;
	unsigned int		newmask = 0;
	int			which;
	int			i;
	int			k;

	/* check validity first before sorting */
	if (aclcheck(aclbufp, nentries, &which) != 0)
		return (-1);

	/*
	 * Performance enhancement:
	 * We change entry type to sort order in the ACL, do the sorting.
	 * We then change sort order back to entry type.
	 * This makes entrycmp() very "light" and thus improves performance.
	 * Contrast to original implementation that had to find out
	 * the sorting order each time it is called.
	 */
	for (tp = aclbufp, i = 0; i < nentries; tp++, i++) {
		for (k = 1; k <= TOTAL_ENTRY_TYPES; k++) {
			if (tp->a_type == map_to_sort[k].entry_type) {
				tp->a_type = map_to_sort[k].sort_order;
				break;
			}
		}
	}

	/* typecast to remove incompatible type warning */
	qsort(aclbufp, nentries, sizeof (aclent_t),
	    (int (*)(const void *, const void *))entrycmp);

	for (tp = aclbufp, i = 0; i < nentries; tp++, i++) {
		for (k = 1; k <= TOTAL_ENTRY_TYPES; k++) {
			if (tp->a_type == map_to_sort[k].sort_order) {
				tp->a_type = map_to_sort[k].entry_type;
				break;
			}
		}
	}

	/*
	 * Start sorting id within USER and GROUP
	 * sortid() could return a pointer and entries left
	 * so that we dont have to search from the beginning
	 *  every time it calls
	 */
	sortid(aclbufp, nentries, USER);
	sortid(aclbufp, nentries, GROUP);
	sortid(aclbufp, nentries, DEF_USER);
	sortid(aclbufp, nentries, DEF_GROUP);

	/*
	 * Recalculate mask entry
	 */
	if (calcmask != 0) {
		/*
		 * At this point, ACL is valid and sorted. We may find a
		 * CLASS_OBJ entry and stop. Because of the case of minimum ACL,
		 * we still have to check till OTHER_OBJ entry is shown.
		 */
		for (tp = aclbufp; tp->a_type != OTHER_OBJ; tp++) {
			if (tp->a_type == USER || tp->a_type == GROUP ||
			    tp->a_type == GROUP_OBJ)
				newmask |= tp->a_perm;
			if (tp->a_type == CLASS_OBJ)
				break;
		}
		if (tp->a_type == CLASS_OBJ)
			tp->a_perm = (unsigned char)newmask;
	}
	return (0);
}

/*
 * sortid() sorts the ids with the same entry type in increasing order
 */
static void
sortid(aclent_t *ap, int cnt, int type)
{
	aclent_t	*tp;
	aclent_t	*startp; /* start of the desired entry type */
	int		howmany;

	for (tp = ap; cnt-- > 0; tp++) {
		if (tp->a_type != type)
			continue;
		startp = tp;
		howmany = 1;
		for (tp++, cnt--; cnt > 0 && tp->a_type == type; tp++, cnt--)
			howmany++;
		/* typecast to remove incompatible type warning */
		qsort(startp, howmany, sizeof (aclent_t),
		    (int (*)(const void*, const void*))idcmp);
	}
}

/*
 * compare the field a_type
 */
static int
entrycmp(const aclent_t *i, const aclent_t *j)
{
	return ((int)(i->a_type) - (int)(j->a_type));
}

/*
 * compare the field a_id
 */
static int
idcmp(const aclent_t *i, const aclent_t *j)
{
	return ((int)(i->a_id) - (int)(j->a_id));
}