xref: /third_party/selinux/libsepol/src/ebitmap.c (revision 6cd6a6ac)
16cd6a6acSopenharmony_ci
26cd6a6acSopenharmony_ci/* Author : Stephen Smalley, <sds@tycho.nsa.gov> */
36cd6a6acSopenharmony_ci
46cd6a6acSopenharmony_ci/* FLASK */
56cd6a6acSopenharmony_ci
66cd6a6acSopenharmony_ci/*
76cd6a6acSopenharmony_ci * Implementation of the extensible bitmap type.
86cd6a6acSopenharmony_ci */
96cd6a6acSopenharmony_ci
106cd6a6acSopenharmony_ci#include <stdlib.h>
116cd6a6acSopenharmony_ci
126cd6a6acSopenharmony_ci#include <sepol/policydb/ebitmap.h>
136cd6a6acSopenharmony_ci#include <sepol/policydb/policydb.h>
146cd6a6acSopenharmony_ci
156cd6a6acSopenharmony_ci#include "debug.h"
166cd6a6acSopenharmony_ci#include "private.h"
176cd6a6acSopenharmony_ci
186cd6a6acSopenharmony_ciint ebitmap_or(ebitmap_t * dst, const ebitmap_t * e1, const ebitmap_t * e2)
196cd6a6acSopenharmony_ci{
206cd6a6acSopenharmony_ci	const ebitmap_node_t *n1, *n2;
216cd6a6acSopenharmony_ci	ebitmap_node_t *new, *prev;
226cd6a6acSopenharmony_ci
236cd6a6acSopenharmony_ci	ebitmap_init(dst);
246cd6a6acSopenharmony_ci
256cd6a6acSopenharmony_ci	n1 = e1->node;
266cd6a6acSopenharmony_ci	n2 = e2->node;
276cd6a6acSopenharmony_ci	prev = 0;
286cd6a6acSopenharmony_ci	while (n1 || n2) {
296cd6a6acSopenharmony_ci		new = (ebitmap_node_t *) malloc(sizeof(ebitmap_node_t));
306cd6a6acSopenharmony_ci		if (!new) {
316cd6a6acSopenharmony_ci			ebitmap_destroy(dst);
326cd6a6acSopenharmony_ci			return -ENOMEM;
336cd6a6acSopenharmony_ci		}
346cd6a6acSopenharmony_ci		if (n1 && n2 && n1->startbit == n2->startbit) {
356cd6a6acSopenharmony_ci			new->startbit = n1->startbit;
366cd6a6acSopenharmony_ci			new->map = n1->map | n2->map;
376cd6a6acSopenharmony_ci			n1 = n1->next;
386cd6a6acSopenharmony_ci			n2 = n2->next;
396cd6a6acSopenharmony_ci		} else if (!n2 || (n1 && n1->startbit < n2->startbit)) {
406cd6a6acSopenharmony_ci			new->startbit = n1->startbit;
416cd6a6acSopenharmony_ci			new->map = n1->map;
426cd6a6acSopenharmony_ci			n1 = n1->next;
436cd6a6acSopenharmony_ci		} else {
446cd6a6acSopenharmony_ci			new->startbit = n2->startbit;
456cd6a6acSopenharmony_ci			new->map = n2->map;
466cd6a6acSopenharmony_ci			n2 = n2->next;
476cd6a6acSopenharmony_ci		}
486cd6a6acSopenharmony_ci
496cd6a6acSopenharmony_ci		new->next = 0;
506cd6a6acSopenharmony_ci		if (prev)
516cd6a6acSopenharmony_ci			prev->next = new;
526cd6a6acSopenharmony_ci		else
536cd6a6acSopenharmony_ci			dst->node = new;
546cd6a6acSopenharmony_ci		prev = new;
556cd6a6acSopenharmony_ci	}
566cd6a6acSopenharmony_ci
576cd6a6acSopenharmony_ci	dst->highbit = (e1->highbit > e2->highbit) ? e1->highbit : e2->highbit;
586cd6a6acSopenharmony_ci	return 0;
596cd6a6acSopenharmony_ci}
606cd6a6acSopenharmony_ci
616cd6a6acSopenharmony_ciint ebitmap_union(ebitmap_t * dst, const ebitmap_t * e1)
626cd6a6acSopenharmony_ci{
636cd6a6acSopenharmony_ci	ebitmap_t tmp;
646cd6a6acSopenharmony_ci
656cd6a6acSopenharmony_ci	if (ebitmap_or(&tmp, dst, e1))
666cd6a6acSopenharmony_ci		return -1;
676cd6a6acSopenharmony_ci	ebitmap_destroy(dst);
686cd6a6acSopenharmony_ci	dst->node = tmp.node;
696cd6a6acSopenharmony_ci	dst->highbit = tmp.highbit;
706cd6a6acSopenharmony_ci
716cd6a6acSopenharmony_ci	return 0;
726cd6a6acSopenharmony_ci}
736cd6a6acSopenharmony_ci
746cd6a6acSopenharmony_ciint ebitmap_and(ebitmap_t *dst, const ebitmap_t *e1, const ebitmap_t *e2)
756cd6a6acSopenharmony_ci{
766cd6a6acSopenharmony_ci	const ebitmap_node_t *n1, *n2;
776cd6a6acSopenharmony_ci	ebitmap_node_t *new, *prev = NULL;
786cd6a6acSopenharmony_ci
796cd6a6acSopenharmony_ci	ebitmap_init(dst);
806cd6a6acSopenharmony_ci
816cd6a6acSopenharmony_ci	n1 = e1->node;
826cd6a6acSopenharmony_ci	n2 = e2->node;
836cd6a6acSopenharmony_ci	while (n1 && n2) {
846cd6a6acSopenharmony_ci		if (n1->startbit == n2->startbit) {
856cd6a6acSopenharmony_ci			if (n1->map & n2->map) {
866cd6a6acSopenharmony_ci				new = malloc(sizeof(ebitmap_node_t));
876cd6a6acSopenharmony_ci				if (!new) {
886cd6a6acSopenharmony_ci					ebitmap_destroy(dst);
896cd6a6acSopenharmony_ci					return -ENOMEM;
906cd6a6acSopenharmony_ci				}
916cd6a6acSopenharmony_ci				new->startbit = n1->startbit;
926cd6a6acSopenharmony_ci				new->map = n1->map & n2->map;
936cd6a6acSopenharmony_ci				new->next = NULL;
946cd6a6acSopenharmony_ci
956cd6a6acSopenharmony_ci				if (prev)
966cd6a6acSopenharmony_ci					prev->next = new;
976cd6a6acSopenharmony_ci				else
986cd6a6acSopenharmony_ci					dst->node = new;
996cd6a6acSopenharmony_ci				prev = new;
1006cd6a6acSopenharmony_ci			}
1016cd6a6acSopenharmony_ci
1026cd6a6acSopenharmony_ci			n1 = n1->next;
1036cd6a6acSopenharmony_ci			n2 = n2->next;
1046cd6a6acSopenharmony_ci		} else if (n1->startbit > n2->startbit) {
1056cd6a6acSopenharmony_ci			n2 = n2->next;
1066cd6a6acSopenharmony_ci		} else {
1076cd6a6acSopenharmony_ci			n1 = n1->next;
1086cd6a6acSopenharmony_ci		}
1096cd6a6acSopenharmony_ci	}
1106cd6a6acSopenharmony_ci
1116cd6a6acSopenharmony_ci	if (prev)
1126cd6a6acSopenharmony_ci		dst->highbit = prev->startbit + MAPSIZE;
1136cd6a6acSopenharmony_ci
1146cd6a6acSopenharmony_ci	return 0;
1156cd6a6acSopenharmony_ci}
1166cd6a6acSopenharmony_ci
1176cd6a6acSopenharmony_ciint ebitmap_xor(ebitmap_t *dst, const ebitmap_t *e1, const ebitmap_t *e2)
1186cd6a6acSopenharmony_ci{
1196cd6a6acSopenharmony_ci	const ebitmap_node_t *n1, *n2;
1206cd6a6acSopenharmony_ci	ebitmap_node_t *new, *prev = NULL;
1216cd6a6acSopenharmony_ci	uint32_t startbit;
1226cd6a6acSopenharmony_ci	MAPTYPE map;
1236cd6a6acSopenharmony_ci
1246cd6a6acSopenharmony_ci	ebitmap_init(dst);
1256cd6a6acSopenharmony_ci
1266cd6a6acSopenharmony_ci	n1 = e1->node;
1276cd6a6acSopenharmony_ci	n2 = e2->node;
1286cd6a6acSopenharmony_ci	while (n1 || n2) {
1296cd6a6acSopenharmony_ci		if (n1 && n2 && n1->startbit == n2->startbit) {
1306cd6a6acSopenharmony_ci			startbit = n1->startbit;
1316cd6a6acSopenharmony_ci			map = n1->map ^ n2->map;
1326cd6a6acSopenharmony_ci			n1 = n1->next;
1336cd6a6acSopenharmony_ci			n2 = n2->next;
1346cd6a6acSopenharmony_ci		} else if (!n2 || (n1 && n1->startbit < n2->startbit)) {
1356cd6a6acSopenharmony_ci			startbit = n1->startbit;
1366cd6a6acSopenharmony_ci			map = n1->map;
1376cd6a6acSopenharmony_ci			n1 = n1->next;
1386cd6a6acSopenharmony_ci		} else {
1396cd6a6acSopenharmony_ci			startbit = n2->startbit;
1406cd6a6acSopenharmony_ci			map = n2->map;
1416cd6a6acSopenharmony_ci			n2 = n2->next;
1426cd6a6acSopenharmony_ci		}
1436cd6a6acSopenharmony_ci
1446cd6a6acSopenharmony_ci		if (map != 0) {
1456cd6a6acSopenharmony_ci			new = malloc(sizeof(ebitmap_node_t));
1466cd6a6acSopenharmony_ci			if (!new) {
1476cd6a6acSopenharmony_ci				ebitmap_destroy(dst);
1486cd6a6acSopenharmony_ci				return -ENOMEM;
1496cd6a6acSopenharmony_ci			}
1506cd6a6acSopenharmony_ci			new->startbit = startbit;
1516cd6a6acSopenharmony_ci			new->map = map;
1526cd6a6acSopenharmony_ci			new->next = NULL;
1536cd6a6acSopenharmony_ci			if (prev)
1546cd6a6acSopenharmony_ci				prev->next = new;
1556cd6a6acSopenharmony_ci			else
1566cd6a6acSopenharmony_ci				dst->node = new;
1576cd6a6acSopenharmony_ci			prev = new;
1586cd6a6acSopenharmony_ci		}
1596cd6a6acSopenharmony_ci	}
1606cd6a6acSopenharmony_ci
1616cd6a6acSopenharmony_ci	if (prev)
1626cd6a6acSopenharmony_ci		dst->highbit = prev->startbit + MAPSIZE;
1636cd6a6acSopenharmony_ci
1646cd6a6acSopenharmony_ci	return 0;
1656cd6a6acSopenharmony_ci}
1666cd6a6acSopenharmony_ci
1676cd6a6acSopenharmony_ciint ebitmap_not(ebitmap_t *dst, const ebitmap_t *e1, unsigned int maxbit)
1686cd6a6acSopenharmony_ci{
1696cd6a6acSopenharmony_ci	const ebitmap_node_t *n;
1706cd6a6acSopenharmony_ci	ebitmap_node_t *new, *prev = NULL;
1716cd6a6acSopenharmony_ci	uint32_t startbit, cur_startbit;
1726cd6a6acSopenharmony_ci	MAPTYPE map;
1736cd6a6acSopenharmony_ci
1746cd6a6acSopenharmony_ci	ebitmap_init(dst);
1756cd6a6acSopenharmony_ci
1766cd6a6acSopenharmony_ci	n = e1->node;
1776cd6a6acSopenharmony_ci	for (cur_startbit = 0; cur_startbit < maxbit; cur_startbit += MAPSIZE) {
1786cd6a6acSopenharmony_ci		if (n && n->startbit == cur_startbit) {
1796cd6a6acSopenharmony_ci			startbit = n->startbit;
1806cd6a6acSopenharmony_ci			map = ~n->map;
1816cd6a6acSopenharmony_ci
1826cd6a6acSopenharmony_ci			n = n->next;
1836cd6a6acSopenharmony_ci		} else {
1846cd6a6acSopenharmony_ci			startbit = cur_startbit;
1856cd6a6acSopenharmony_ci			map = ~((MAPTYPE) 0);
1866cd6a6acSopenharmony_ci		}
1876cd6a6acSopenharmony_ci
1886cd6a6acSopenharmony_ci		if (maxbit - cur_startbit < MAPSIZE)
1896cd6a6acSopenharmony_ci			map &= (((MAPTYPE)1) << (maxbit - cur_startbit)) - 1;
1906cd6a6acSopenharmony_ci
1916cd6a6acSopenharmony_ci		if (map != 0) {
1926cd6a6acSopenharmony_ci			new = malloc(sizeof(ebitmap_node_t));
1936cd6a6acSopenharmony_ci			if (!new) {
1946cd6a6acSopenharmony_ci				ebitmap_destroy(dst);
1956cd6a6acSopenharmony_ci				return -ENOMEM;
1966cd6a6acSopenharmony_ci			}
1976cd6a6acSopenharmony_ci
1986cd6a6acSopenharmony_ci			new->startbit = startbit;
1996cd6a6acSopenharmony_ci			new->map = map;
2006cd6a6acSopenharmony_ci			new->next = NULL;
2016cd6a6acSopenharmony_ci
2026cd6a6acSopenharmony_ci			if (prev)
2036cd6a6acSopenharmony_ci				prev->next = new;
2046cd6a6acSopenharmony_ci			else
2056cd6a6acSopenharmony_ci				dst->node = new;
2066cd6a6acSopenharmony_ci			prev = new;
2076cd6a6acSopenharmony_ci		}
2086cd6a6acSopenharmony_ci	}
2096cd6a6acSopenharmony_ci
2106cd6a6acSopenharmony_ci	if (prev)
2116cd6a6acSopenharmony_ci		dst->highbit = prev->startbit + MAPSIZE;
2126cd6a6acSopenharmony_ci
2136cd6a6acSopenharmony_ci	return 0;
2146cd6a6acSopenharmony_ci}
2156cd6a6acSopenharmony_ci
2166cd6a6acSopenharmony_ciint ebitmap_andnot(ebitmap_t *dst, const ebitmap_t *e1, const ebitmap_t *e2, unsigned int maxbit)
2176cd6a6acSopenharmony_ci{
2186cd6a6acSopenharmony_ci	int rc;
2196cd6a6acSopenharmony_ci	ebitmap_t e3;
2206cd6a6acSopenharmony_ci	ebitmap_init(dst);
2216cd6a6acSopenharmony_ci	rc = ebitmap_not(&e3, e2, maxbit);
2226cd6a6acSopenharmony_ci	if (rc < 0)
2236cd6a6acSopenharmony_ci		return rc;
2246cd6a6acSopenharmony_ci	rc = ebitmap_and(dst, e1, &e3);
2256cd6a6acSopenharmony_ci	ebitmap_destroy(&e3);
2266cd6a6acSopenharmony_ci	if (rc < 0)
2276cd6a6acSopenharmony_ci		return rc;
2286cd6a6acSopenharmony_ci	return 0;
2296cd6a6acSopenharmony_ci}
2306cd6a6acSopenharmony_ci
2316cd6a6acSopenharmony_ciunsigned int ebitmap_cardinality(const ebitmap_t *e1)
2326cd6a6acSopenharmony_ci{
2336cd6a6acSopenharmony_ci	unsigned int count = 0;
2346cd6a6acSopenharmony_ci	const ebitmap_node_t *n;
2356cd6a6acSopenharmony_ci
2366cd6a6acSopenharmony_ci	for (n = e1->node; n; n = n->next) {
2376cd6a6acSopenharmony_ci		count += __builtin_popcountll(n->map);
2386cd6a6acSopenharmony_ci	}
2396cd6a6acSopenharmony_ci	return count;
2406cd6a6acSopenharmony_ci}
2416cd6a6acSopenharmony_ci
2426cd6a6acSopenharmony_ciint ebitmap_hamming_distance(const ebitmap_t * e1, const ebitmap_t * e2)
2436cd6a6acSopenharmony_ci{
2446cd6a6acSopenharmony_ci	int rc;
2456cd6a6acSopenharmony_ci	ebitmap_t tmp;
2466cd6a6acSopenharmony_ci	int distance;
2476cd6a6acSopenharmony_ci	if (ebitmap_cmp(e1, e2))
2486cd6a6acSopenharmony_ci		return 0;
2496cd6a6acSopenharmony_ci	rc = ebitmap_xor(&tmp, e1, e2);
2506cd6a6acSopenharmony_ci	if (rc < 0)
2516cd6a6acSopenharmony_ci		return -1;
2526cd6a6acSopenharmony_ci	distance = ebitmap_cardinality(&tmp);
2536cd6a6acSopenharmony_ci	ebitmap_destroy(&tmp);
2546cd6a6acSopenharmony_ci	return distance;
2556cd6a6acSopenharmony_ci}
2566cd6a6acSopenharmony_ci
2576cd6a6acSopenharmony_ciint ebitmap_cmp(const ebitmap_t * e1, const ebitmap_t * e2)
2586cd6a6acSopenharmony_ci{
2596cd6a6acSopenharmony_ci	const ebitmap_node_t *n1, *n2;
2606cd6a6acSopenharmony_ci
2616cd6a6acSopenharmony_ci	if (e1->highbit != e2->highbit)
2626cd6a6acSopenharmony_ci		return 0;
2636cd6a6acSopenharmony_ci
2646cd6a6acSopenharmony_ci	n1 = e1->node;
2656cd6a6acSopenharmony_ci	n2 = e2->node;
2666cd6a6acSopenharmony_ci	while (n1 && n2 &&
2676cd6a6acSopenharmony_ci	       (n1->startbit == n2->startbit) && (n1->map == n2->map)) {
2686cd6a6acSopenharmony_ci		n1 = n1->next;
2696cd6a6acSopenharmony_ci		n2 = n2->next;
2706cd6a6acSopenharmony_ci	}
2716cd6a6acSopenharmony_ci
2726cd6a6acSopenharmony_ci	if (n1 || n2)
2736cd6a6acSopenharmony_ci		return 0;
2746cd6a6acSopenharmony_ci
2756cd6a6acSopenharmony_ci	return 1;
2766cd6a6acSopenharmony_ci}
2776cd6a6acSopenharmony_ci
2786cd6a6acSopenharmony_ciint ebitmap_cpy(ebitmap_t * dst, const ebitmap_t * src)
2796cd6a6acSopenharmony_ci{
2806cd6a6acSopenharmony_ci	const ebitmap_node_t *n;
2816cd6a6acSopenharmony_ci	ebitmap_node_t *new, *prev;
2826cd6a6acSopenharmony_ci
2836cd6a6acSopenharmony_ci	ebitmap_init(dst);
2846cd6a6acSopenharmony_ci	n = src->node;
2856cd6a6acSopenharmony_ci	prev = 0;
2866cd6a6acSopenharmony_ci	while (n) {
2876cd6a6acSopenharmony_ci		new = (ebitmap_node_t *) malloc(sizeof(ebitmap_node_t));
2886cd6a6acSopenharmony_ci		if (!new) {
2896cd6a6acSopenharmony_ci			ebitmap_destroy(dst);
2906cd6a6acSopenharmony_ci			return -ENOMEM;
2916cd6a6acSopenharmony_ci		}
2926cd6a6acSopenharmony_ci		new->startbit = n->startbit;
2936cd6a6acSopenharmony_ci		new->map = n->map;
2946cd6a6acSopenharmony_ci		new->next = 0;
2956cd6a6acSopenharmony_ci		if (prev)
2966cd6a6acSopenharmony_ci			prev->next = new;
2976cd6a6acSopenharmony_ci		else
2986cd6a6acSopenharmony_ci			dst->node = new;
2996cd6a6acSopenharmony_ci		prev = new;
3006cd6a6acSopenharmony_ci		n = n->next;
3016cd6a6acSopenharmony_ci	}
3026cd6a6acSopenharmony_ci
3036cd6a6acSopenharmony_ci	dst->highbit = src->highbit;
3046cd6a6acSopenharmony_ci	return 0;
3056cd6a6acSopenharmony_ci}
3066cd6a6acSopenharmony_ci
3076cd6a6acSopenharmony_ciint ebitmap_contains(const ebitmap_t * e1, const ebitmap_t * e2)
3086cd6a6acSopenharmony_ci{
3096cd6a6acSopenharmony_ci	const ebitmap_node_t *n1, *n2;
3106cd6a6acSopenharmony_ci
3116cd6a6acSopenharmony_ci	if (e1->highbit < e2->highbit)
3126cd6a6acSopenharmony_ci		return 0;
3136cd6a6acSopenharmony_ci
3146cd6a6acSopenharmony_ci	n1 = e1->node;
3156cd6a6acSopenharmony_ci	n2 = e2->node;
3166cd6a6acSopenharmony_ci	while (n1 && n2 && (n1->startbit <= n2->startbit)) {
3176cd6a6acSopenharmony_ci		if (n1->startbit < n2->startbit) {
3186cd6a6acSopenharmony_ci			n1 = n1->next;
3196cd6a6acSopenharmony_ci			continue;
3206cd6a6acSopenharmony_ci		}
3216cd6a6acSopenharmony_ci		if ((n1->map & n2->map) != n2->map)
3226cd6a6acSopenharmony_ci			return 0;
3236cd6a6acSopenharmony_ci
3246cd6a6acSopenharmony_ci		n1 = n1->next;
3256cd6a6acSopenharmony_ci		n2 = n2->next;
3266cd6a6acSopenharmony_ci	}
3276cd6a6acSopenharmony_ci
3286cd6a6acSopenharmony_ci	if (n2)
3296cd6a6acSopenharmony_ci		return 0;
3306cd6a6acSopenharmony_ci
3316cd6a6acSopenharmony_ci	return 1;
3326cd6a6acSopenharmony_ci}
3336cd6a6acSopenharmony_ci
3346cd6a6acSopenharmony_ciint ebitmap_match_any(const ebitmap_t *e1, const ebitmap_t *e2)
3356cd6a6acSopenharmony_ci{
3366cd6a6acSopenharmony_ci	const ebitmap_node_t *n1 = e1->node;
3376cd6a6acSopenharmony_ci	const ebitmap_node_t *n2 = e2->node;
3386cd6a6acSopenharmony_ci
3396cd6a6acSopenharmony_ci	while (n1 && n2) {
3406cd6a6acSopenharmony_ci		if (n1->startbit < n2->startbit) {
3416cd6a6acSopenharmony_ci			n1 = n1->next;
3426cd6a6acSopenharmony_ci		} else if (n2->startbit < n1->startbit) {
3436cd6a6acSopenharmony_ci			n2 = n2->next;
3446cd6a6acSopenharmony_ci		} else {
3456cd6a6acSopenharmony_ci			if (n1->map & n2->map) {
3466cd6a6acSopenharmony_ci				return 1;
3476cd6a6acSopenharmony_ci			}
3486cd6a6acSopenharmony_ci			n1 = n1->next;
3496cd6a6acSopenharmony_ci			n2 = n2->next;
3506cd6a6acSopenharmony_ci		}
3516cd6a6acSopenharmony_ci	}
3526cd6a6acSopenharmony_ci
3536cd6a6acSopenharmony_ci	return 0;
3546cd6a6acSopenharmony_ci}
3556cd6a6acSopenharmony_ci
3566cd6a6acSopenharmony_ciint ebitmap_get_bit(const ebitmap_t * e, unsigned int bit)
3576cd6a6acSopenharmony_ci{
3586cd6a6acSopenharmony_ci	const ebitmap_node_t *n;
3596cd6a6acSopenharmony_ci
3606cd6a6acSopenharmony_ci	if (e->highbit < bit)
3616cd6a6acSopenharmony_ci		return 0;
3626cd6a6acSopenharmony_ci
3636cd6a6acSopenharmony_ci	n = e->node;
3646cd6a6acSopenharmony_ci	while (n && (n->startbit <= bit)) {
3656cd6a6acSopenharmony_ci		if ((n->startbit + MAPSIZE) > bit) {
3666cd6a6acSopenharmony_ci			if (n->map & (MAPBIT << (bit - n->startbit)))
3676cd6a6acSopenharmony_ci				return 1;
3686cd6a6acSopenharmony_ci			else
3696cd6a6acSopenharmony_ci				return 0;
3706cd6a6acSopenharmony_ci		}
3716cd6a6acSopenharmony_ci		n = n->next;
3726cd6a6acSopenharmony_ci	}
3736cd6a6acSopenharmony_ci
3746cd6a6acSopenharmony_ci	return 0;
3756cd6a6acSopenharmony_ci}
3766cd6a6acSopenharmony_ci
3776cd6a6acSopenharmony_ciint ebitmap_set_bit(ebitmap_t * e, unsigned int bit, int value)
3786cd6a6acSopenharmony_ci{
3796cd6a6acSopenharmony_ci	ebitmap_node_t *n, *prev, *new;
3806cd6a6acSopenharmony_ci	uint32_t startbit = bit & ~(MAPSIZE - 1);
3816cd6a6acSopenharmony_ci	uint32_t highbit = startbit + MAPSIZE;
3826cd6a6acSopenharmony_ci
3836cd6a6acSopenharmony_ci	if (highbit == 0) {
3846cd6a6acSopenharmony_ci		ERR(NULL, "bitmap overflow, bit 0x%x", bit);
3856cd6a6acSopenharmony_ci		return -EINVAL;
3866cd6a6acSopenharmony_ci	}
3876cd6a6acSopenharmony_ci
3886cd6a6acSopenharmony_ci	prev = 0;
3896cd6a6acSopenharmony_ci	n = e->node;
3906cd6a6acSopenharmony_ci	while (n && n->startbit <= bit) {
3916cd6a6acSopenharmony_ci		if ((n->startbit + MAPSIZE) > bit) {
3926cd6a6acSopenharmony_ci			if (value) {
3936cd6a6acSopenharmony_ci				n->map |= (MAPBIT << (bit - n->startbit));
3946cd6a6acSopenharmony_ci			} else {
3956cd6a6acSopenharmony_ci				n->map &= ~(MAPBIT << (bit - n->startbit));
3966cd6a6acSopenharmony_ci				if (!n->map) {
3976cd6a6acSopenharmony_ci					/* drop this node from the bitmap */
3986cd6a6acSopenharmony_ci
3996cd6a6acSopenharmony_ci					if (!n->next) {
4006cd6a6acSopenharmony_ci						/*
4016cd6a6acSopenharmony_ci						 * this was the highest map
4026cd6a6acSopenharmony_ci						 * within the bitmap
4036cd6a6acSopenharmony_ci						 */
4046cd6a6acSopenharmony_ci						if (prev)
4056cd6a6acSopenharmony_ci							e->highbit =
4066cd6a6acSopenharmony_ci							    prev->startbit +
4076cd6a6acSopenharmony_ci							    MAPSIZE;
4086cd6a6acSopenharmony_ci						else
4096cd6a6acSopenharmony_ci							e->highbit = 0;
4106cd6a6acSopenharmony_ci					}
4116cd6a6acSopenharmony_ci					if (prev)
4126cd6a6acSopenharmony_ci						prev->next = n->next;
4136cd6a6acSopenharmony_ci					else
4146cd6a6acSopenharmony_ci						e->node = n->next;
4156cd6a6acSopenharmony_ci
4166cd6a6acSopenharmony_ci					free(n);
4176cd6a6acSopenharmony_ci				}
4186cd6a6acSopenharmony_ci			}
4196cd6a6acSopenharmony_ci			return 0;
4206cd6a6acSopenharmony_ci		}
4216cd6a6acSopenharmony_ci		prev = n;
4226cd6a6acSopenharmony_ci		n = n->next;
4236cd6a6acSopenharmony_ci	}
4246cd6a6acSopenharmony_ci
4256cd6a6acSopenharmony_ci	if (!value)
4266cd6a6acSopenharmony_ci		return 0;
4276cd6a6acSopenharmony_ci
4286cd6a6acSopenharmony_ci	new = (ebitmap_node_t *) malloc(sizeof(ebitmap_node_t));
4296cd6a6acSopenharmony_ci	if (!new)
4306cd6a6acSopenharmony_ci		return -ENOMEM;
4316cd6a6acSopenharmony_ci
4326cd6a6acSopenharmony_ci	new->startbit = startbit;
4336cd6a6acSopenharmony_ci	new->map = (MAPBIT << (bit - new->startbit));
4346cd6a6acSopenharmony_ci
4356cd6a6acSopenharmony_ci	if (!n) {
4366cd6a6acSopenharmony_ci		/* this node will be the highest map within the bitmap */
4376cd6a6acSopenharmony_ci		e->highbit = highbit;
4386cd6a6acSopenharmony_ci	}
4396cd6a6acSopenharmony_ci
4406cd6a6acSopenharmony_ci	if (prev) {
4416cd6a6acSopenharmony_ci		new->next = prev->next;
4426cd6a6acSopenharmony_ci		prev->next = new;
4436cd6a6acSopenharmony_ci	} else {
4446cd6a6acSopenharmony_ci		new->next = e->node;
4456cd6a6acSopenharmony_ci		e->node = new;
4466cd6a6acSopenharmony_ci	}
4476cd6a6acSopenharmony_ci
4486cd6a6acSopenharmony_ci	return 0;
4496cd6a6acSopenharmony_ci}
4506cd6a6acSopenharmony_ci
4516cd6a6acSopenharmony_ciint ebitmap_init_range(ebitmap_t * e, unsigned int minbit, unsigned int maxbit)
4526cd6a6acSopenharmony_ci{
4536cd6a6acSopenharmony_ci	ebitmap_node_t *new, *prev = NULL;
4546cd6a6acSopenharmony_ci	uint32_t minstartbit = minbit & ~(MAPSIZE - 1);
4556cd6a6acSopenharmony_ci	uint32_t maxstartbit = maxbit & ~(MAPSIZE - 1);
4566cd6a6acSopenharmony_ci	uint32_t minhighbit = minstartbit + MAPSIZE;
4576cd6a6acSopenharmony_ci	uint32_t maxhighbit = maxstartbit + MAPSIZE;
4586cd6a6acSopenharmony_ci	uint32_t startbit;
4596cd6a6acSopenharmony_ci	MAPTYPE mask;
4606cd6a6acSopenharmony_ci
4616cd6a6acSopenharmony_ci	ebitmap_init(e);
4626cd6a6acSopenharmony_ci
4636cd6a6acSopenharmony_ci	if (minbit > maxbit)
4646cd6a6acSopenharmony_ci		return -EINVAL;
4656cd6a6acSopenharmony_ci
4666cd6a6acSopenharmony_ci	if (minhighbit == 0 || maxhighbit == 0)
4676cd6a6acSopenharmony_ci		return -EOVERFLOW;
4686cd6a6acSopenharmony_ci
4696cd6a6acSopenharmony_ci	for (startbit = minstartbit; startbit <= maxstartbit; startbit += MAPSIZE) {
4706cd6a6acSopenharmony_ci		new = malloc(sizeof(ebitmap_node_t));
4716cd6a6acSopenharmony_ci		if (!new)
4726cd6a6acSopenharmony_ci			return -ENOMEM;
4736cd6a6acSopenharmony_ci
4746cd6a6acSopenharmony_ci		new->next = NULL;
4756cd6a6acSopenharmony_ci		new->startbit = startbit;
4766cd6a6acSopenharmony_ci
4776cd6a6acSopenharmony_ci		if (startbit != minstartbit && startbit != maxstartbit) {
4786cd6a6acSopenharmony_ci			new->map = ~((MAPTYPE)0);
4796cd6a6acSopenharmony_ci		} else if (startbit != maxstartbit) {
4806cd6a6acSopenharmony_ci			new->map = ~((MAPTYPE)0) << (minbit - startbit);
4816cd6a6acSopenharmony_ci		} else if (startbit != minstartbit) {
4826cd6a6acSopenharmony_ci			new->map = ~((MAPTYPE)0) >> (MAPSIZE - (maxbit - startbit + 1));
4836cd6a6acSopenharmony_ci		} else {
4846cd6a6acSopenharmony_ci			mask = ~((MAPTYPE)0) >> (MAPSIZE - (maxbit - minbit + 1));
4856cd6a6acSopenharmony_ci			new->map = (mask << (minbit - startbit));
4866cd6a6acSopenharmony_ci		}
4876cd6a6acSopenharmony_ci
4886cd6a6acSopenharmony_ci		if (prev)
4896cd6a6acSopenharmony_ci			prev->next = new;
4906cd6a6acSopenharmony_ci		else
4916cd6a6acSopenharmony_ci			e->node = new;
4926cd6a6acSopenharmony_ci		prev = new;
4936cd6a6acSopenharmony_ci	}
4946cd6a6acSopenharmony_ci
4956cd6a6acSopenharmony_ci	e->highbit = maxhighbit;
4966cd6a6acSopenharmony_ci
4976cd6a6acSopenharmony_ci	return 0;
4986cd6a6acSopenharmony_ci}
4996cd6a6acSopenharmony_ci
5006cd6a6acSopenharmony_ciunsigned int ebitmap_highest_set_bit(const ebitmap_t * e)
5016cd6a6acSopenharmony_ci{
5026cd6a6acSopenharmony_ci	const ebitmap_node_t *n;
5036cd6a6acSopenharmony_ci	MAPTYPE map;
5046cd6a6acSopenharmony_ci	unsigned int pos = 0;
5056cd6a6acSopenharmony_ci
5066cd6a6acSopenharmony_ci	n = e->node;
5076cd6a6acSopenharmony_ci	if (!n)
5086cd6a6acSopenharmony_ci		return 0;
5096cd6a6acSopenharmony_ci
5106cd6a6acSopenharmony_ci	while (n->next)
5116cd6a6acSopenharmony_ci		n = n->next;
5126cd6a6acSopenharmony_ci
5136cd6a6acSopenharmony_ci	map = n->map;
5146cd6a6acSopenharmony_ci	while (map >>= 1)
5156cd6a6acSopenharmony_ci		pos++;
5166cd6a6acSopenharmony_ci
5176cd6a6acSopenharmony_ci	return n->startbit + pos;
5186cd6a6acSopenharmony_ci}
5196cd6a6acSopenharmony_ci
5206cd6a6acSopenharmony_civoid ebitmap_destroy(ebitmap_t * e)
5216cd6a6acSopenharmony_ci{
5226cd6a6acSopenharmony_ci	ebitmap_node_t *n, *temp;
5236cd6a6acSopenharmony_ci
5246cd6a6acSopenharmony_ci	if (!e)
5256cd6a6acSopenharmony_ci		return;
5266cd6a6acSopenharmony_ci
5276cd6a6acSopenharmony_ci	n = e->node;
5286cd6a6acSopenharmony_ci	while (n) {
5296cd6a6acSopenharmony_ci		temp = n;
5306cd6a6acSopenharmony_ci		n = n->next;
5316cd6a6acSopenharmony_ci		free(temp);
5326cd6a6acSopenharmony_ci	}
5336cd6a6acSopenharmony_ci
5346cd6a6acSopenharmony_ci	e->highbit = 0;
5356cd6a6acSopenharmony_ci	e->node = 0;
5366cd6a6acSopenharmony_ci	return;
5376cd6a6acSopenharmony_ci}
5386cd6a6acSopenharmony_ci
5396cd6a6acSopenharmony_ciint ebitmap_read(ebitmap_t * e, void *fp)
5406cd6a6acSopenharmony_ci{
5416cd6a6acSopenharmony_ci	int rc;
5426cd6a6acSopenharmony_ci	ebitmap_node_t *n, *l;
5436cd6a6acSopenharmony_ci	uint32_t buf[3], mapsize, count, i;
5446cd6a6acSopenharmony_ci	uint64_t map;
5456cd6a6acSopenharmony_ci
5466cd6a6acSopenharmony_ci	ebitmap_init(e);
5476cd6a6acSopenharmony_ci
5486cd6a6acSopenharmony_ci	rc = next_entry(buf, fp, sizeof(uint32_t) * 3);
5496cd6a6acSopenharmony_ci	if (rc < 0)
5506cd6a6acSopenharmony_ci		goto bad;
5516cd6a6acSopenharmony_ci
5526cd6a6acSopenharmony_ci	mapsize = le32_to_cpu(buf[0]);
5536cd6a6acSopenharmony_ci	e->highbit = le32_to_cpu(buf[1]);
5546cd6a6acSopenharmony_ci	count = le32_to_cpu(buf[2]);
5556cd6a6acSopenharmony_ci
5566cd6a6acSopenharmony_ci	if (mapsize != MAPSIZE) {
5576cd6a6acSopenharmony_ci		ERR(NULL, "security: ebitmap: map size %d does not match my size %zu (high bit was %d)",
5586cd6a6acSopenharmony_ci		     mapsize, MAPSIZE, e->highbit);
5596cd6a6acSopenharmony_ci		goto bad;
5606cd6a6acSopenharmony_ci	}
5616cd6a6acSopenharmony_ci	if (!e->highbit) {
5626cd6a6acSopenharmony_ci		e->node = NULL;
5636cd6a6acSopenharmony_ci		goto ok;
5646cd6a6acSopenharmony_ci	}
5656cd6a6acSopenharmony_ci	if (e->highbit & (MAPSIZE - 1)) {
5666cd6a6acSopenharmony_ci		ERR(NULL, "security: ebitmap: high bit (%d) is not a multiple of the map size (%zu)",
5676cd6a6acSopenharmony_ci		     e->highbit, MAPSIZE);
5686cd6a6acSopenharmony_ci		goto bad;
5696cd6a6acSopenharmony_ci	}
5706cd6a6acSopenharmony_ci
5716cd6a6acSopenharmony_ci	if (e->highbit && !count)
5726cd6a6acSopenharmony_ci		goto bad;
5736cd6a6acSopenharmony_ci
5746cd6a6acSopenharmony_ci	l = NULL;
5756cd6a6acSopenharmony_ci	for (i = 0; i < count; i++) {
5766cd6a6acSopenharmony_ci		rc = next_entry(buf, fp, sizeof(uint32_t));
5776cd6a6acSopenharmony_ci		if (rc < 0) {
5786cd6a6acSopenharmony_ci			ERR(NULL, "security: ebitmap: truncated map");
5796cd6a6acSopenharmony_ci			goto bad;
5806cd6a6acSopenharmony_ci		}
5816cd6a6acSopenharmony_ci		n = (ebitmap_node_t *) malloc(sizeof(ebitmap_node_t));
5826cd6a6acSopenharmony_ci		if (!n) {
5836cd6a6acSopenharmony_ci			ERR(NULL, "security: ebitmap: out of memory");
5846cd6a6acSopenharmony_ci			rc = -ENOMEM;
5856cd6a6acSopenharmony_ci			goto bad;
5866cd6a6acSopenharmony_ci		}
5876cd6a6acSopenharmony_ci		memset(n, 0, sizeof(ebitmap_node_t));
5886cd6a6acSopenharmony_ci
5896cd6a6acSopenharmony_ci		n->startbit = le32_to_cpu(buf[0]);
5906cd6a6acSopenharmony_ci
5916cd6a6acSopenharmony_ci		if (n->startbit & (MAPSIZE - 1)) {
5926cd6a6acSopenharmony_ci			ERR(NULL, "security: ebitmap start bit (%d) is not a multiple of the map size (%zu)",
5936cd6a6acSopenharmony_ci			     n->startbit, MAPSIZE);
5946cd6a6acSopenharmony_ci			goto bad_free;
5956cd6a6acSopenharmony_ci		}
5966cd6a6acSopenharmony_ci		if (n->startbit > (e->highbit - MAPSIZE)) {
5976cd6a6acSopenharmony_ci			ERR(NULL, "security: ebitmap start bit (%d) is beyond the end of the bitmap (%zu)",
5986cd6a6acSopenharmony_ci			     n->startbit, (e->highbit - MAPSIZE));
5996cd6a6acSopenharmony_ci			goto bad_free;
6006cd6a6acSopenharmony_ci		}
6016cd6a6acSopenharmony_ci		rc = next_entry(&map, fp, sizeof(uint64_t));
6026cd6a6acSopenharmony_ci		if (rc < 0) {
6036cd6a6acSopenharmony_ci			ERR(NULL, "security: ebitmap: truncated map");
6046cd6a6acSopenharmony_ci			goto bad_free;
6056cd6a6acSopenharmony_ci		}
6066cd6a6acSopenharmony_ci		n->map = le64_to_cpu(map);
6076cd6a6acSopenharmony_ci
6086cd6a6acSopenharmony_ci		if (!n->map) {
6096cd6a6acSopenharmony_ci			ERR(NULL, "security: ebitmap: null map in ebitmap (startbit %d)",
6106cd6a6acSopenharmony_ci			     n->startbit);
6116cd6a6acSopenharmony_ci			goto bad_free;
6126cd6a6acSopenharmony_ci		}
6136cd6a6acSopenharmony_ci		if (l) {
6146cd6a6acSopenharmony_ci			if (n->startbit <= l->startbit) {
6156cd6a6acSopenharmony_ci				ERR(NULL, "security: ebitmap: start bit %d comes after start bit %d",
6166cd6a6acSopenharmony_ci				     n->startbit, l->startbit);
6176cd6a6acSopenharmony_ci				goto bad_free;
6186cd6a6acSopenharmony_ci			}
6196cd6a6acSopenharmony_ci			l->next = n;
6206cd6a6acSopenharmony_ci		} else
6216cd6a6acSopenharmony_ci			e->node = n;
6226cd6a6acSopenharmony_ci
6236cd6a6acSopenharmony_ci		l = n;
6246cd6a6acSopenharmony_ci	}
6256cd6a6acSopenharmony_ci	if (count && l->startbit + MAPSIZE != e->highbit) {
6266cd6a6acSopenharmony_ci		ERR(NULL, "security: ebitmap: high bit %u has not the expected value %zu",
6276cd6a6acSopenharmony_ci		     e->highbit, l->startbit + MAPSIZE);
6286cd6a6acSopenharmony_ci		goto bad;
6296cd6a6acSopenharmony_ci	}
6306cd6a6acSopenharmony_ci
6316cd6a6acSopenharmony_ci      ok:
6326cd6a6acSopenharmony_ci	rc = 0;
6336cd6a6acSopenharmony_ci      out:
6346cd6a6acSopenharmony_ci	return rc;
6356cd6a6acSopenharmony_ci      bad_free:
6366cd6a6acSopenharmony_ci	free(n);
6376cd6a6acSopenharmony_ci      bad:
6386cd6a6acSopenharmony_ci	if (!rc)
6396cd6a6acSopenharmony_ci		rc = -EINVAL;
6406cd6a6acSopenharmony_ci	ebitmap_destroy(e);
6416cd6a6acSopenharmony_ci	goto out;
6426cd6a6acSopenharmony_ci}
6436cd6a6acSopenharmony_ci
6446cd6a6acSopenharmony_ci/* FLASK */
645