text: /* Authors: Joshua Brindle <jbrindle@tresys.com>
   * 	    Jason Tang <jtang@tresys.com>
   *
   * Copyright (C) 2005-2006 Tresys Technology, LLC
   *
   *  This library is free software; you can redistribute it and/or
   *  modify it under the terms of the GNU Lesser General Public
   *  License as published by the Free Software Foundation; either
   *  version 2.1 of the License, or (at your option) any later version.
   *
   *  This library is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   *  Lesser General Public License for more details.
   *
   *  You should have received a copy of the GNU Lesser General Public
   *  License along with this library; if not, write to the Free Software
   *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   */
  
  #include <assert.h>
  #include <stdio.h>
  #include <stdlib.h>
  
  #include <sepol/policydb/flask_types.h>
  #include <sepol/policydb/policydb.h>
  
  struct val_to_name {
  	unsigned int val;
  	char *name;
  };
  
  /* Add an unsigned integer to a dynamically reallocated array.  *cnt
   * is a reference pointer to the number of values already within array
   * *a; it will be incremented upon successfully appending i.  If *a is
   * NULL then this function will create a new array (*cnt is reset to
   * 0).  Return 0 on success, -1 on out of memory. */
  int add_i_to_a(uint32_t i, uint32_t * cnt, uint32_t ** a)
  {
  	if (cnt == NULL || a == NULL)
  		return -1;
  
  	/* FIX ME: This is not very elegant! We use an array that we
  	 * grow as new uint32_t are added to an array.  But rather
  	 * than be smart about it, for now we realloc() the array each
  	 * time a new uint32_t is added! */
  	if (*a != NULL)
  		*a = (uint32_t *) realloc(*a, (*cnt + 1) * sizeof(uint32_t));
  	else {			/* empty list */
  
  		*cnt = 0;
  		*a = (uint32_t *) malloc(sizeof(uint32_t));
  	}
  	if (*a == NULL) {
  		return -1;
  	}
  	(*a)[*cnt] = i;
  	(*cnt)++;
  	return 0;
  }
  
  static int perm_name(hashtab_key_t key, hashtab_datum_t datum, void *data)
  {
  	struct val_to_name *v = data;
  	perm_datum_t *perdatum;
  
  	perdatum = (perm_datum_t *) datum;
  
  	if (v->val == perdatum->s.value) {
  		v->name = key;
  		return 1;
  	}
  
  	return 0;
  }
  
  char *sepol_av_to_string(policydb_t * policydbp, uint32_t tclass,
  			 sepol_access_vector_t av)
  {
  	struct val_to_name v;
  	static char avbuf[1024];
  	class_datum_t *cladatum;
  	char *perm = NULL, *p;
  	unsigned int i;
  	int rc;
  	int avlen = 0, len;
  
  	cladatum = policydbp->class_val_to_struct[tclass - 1];
  	p = avbuf;
  	for (i = 0; i < cladatum->permissions.nprim; i++) {
  		if (av & (1 << i)) {
  			v.val = i + 1;
  			rc = hashtab_map(cladatum->permissions.table,
  					 perm_name, &v);
  			if (!rc && cladatum->comdatum) {
  				rc = hashtab_map(cladatum->comdatum->
  						 permissions.table, perm_name,
  						 &v);
  			}
  			if (rc)
  				perm = v.name;
  			if (perm) {
  				len =
  				    snprintf(p, sizeof(avbuf) - avlen, " %s",
  					     perm);
  				if (len < 0
  				    || (size_t) len >= (sizeof(avbuf) - avlen))
  					return NULL;
  				p += len;
  				avlen += len;
  			}
  		}
  	}
  
  	return avbuf;
  }
  