/*
  Copyright (C) 2000, 2002, 2003  Andreas Gruenbacher <agruen@suse.de>

  This program 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 program 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 program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "config.h"
#include <errno.h>
#include <sys/acl.h>
#include <acl/libacl.h>
#include <errno.h>
#include "libobj.h"

#ifndef ENOATTR
# define ENOATTR ENODATA
#endif

typedef unsigned int permset_t;

#define ACL_PERM_NONE		(0x0000)

/* object types */
struct acl_permset_obj_tag;
typedef struct acl_permset_obj_tag acl_permset_obj;
struct qualifier_obj_tag;
typedef struct qualifier_obj_tag qualifier_obj;
struct acl_entry_obj_tag;
typedef struct acl_entry_obj_tag acl_entry_obj;
struct acl_obj_tag;
typedef struct acl_obj_tag acl_obj;

/* permset_t object */
struct __acl_permset_ext {
	permset_t		s_perm;
};
struct acl_permset_obj_tag {
	obj_prefix		o_prefix;
	struct __acl_permset_ext i;
};

#define sperm i.s_perm
#define oprefix i.o_prefix

#define permset_obj_equal(s1, s2) \
	((s1).sperm == (s2).sperm)

/* qualifier object */
struct __qualifier_ext {
        id_t                    q_id;
};

struct qualifier_obj_tag {
	obj_prefix		o_prefix;
	struct __qualifier_ext	i;
};

#define qid i.q_id

#define qualifier_obj_id(q) \
	((q).qid)

/* acl_entry object */
struct __acl_entry {
	acl_tag_t		e_tag;
	qualifier_obj		e_id;
	acl_permset_obj		e_perm;
};

struct __acl_entry_ext {
	acl_entry_obj		*e_prev, *e_next;
	acl_obj			*e_container;
	struct __acl_entry	e_entry;
};

struct acl_entry_obj_tag {
	obj_prefix              o_prefix;
	struct __acl_entry_ext	i;
};
	
#define econtainer i.e_container
#define eprev i.e_prev
#define enext i.e_next
#define eentry i.e_entry
#define etag i.e_entry.e_tag
#define eperm i.e_entry.e_perm
#define eid   i.e_entry.e_id

#define init_acl_entry_obj(entry) do { \
	(entry).etag = ACL_UNDEFINED_TAG; \
	new_obj_p_here(acl_permset, &(entry).eperm); \
	(entry).eperm.sperm = ACL_PERM_NONE; \
	new_obj_p_here(qualifier, &(entry).eid); \
	(entry).eid.qid = ACL_UNDEFINED_ID; \
	} while(0)

/* acl object */
struct __acl_ext {
	acl_entry_obj		*a_prev, *a_next;
	acl_entry_obj		*a_curr;
	acl_entry_obj		*a_prealloc, *a_prealloc_end;
	size_t			a_used;
};
struct acl_obj_tag {
	obj_prefix              o_prefix;
	struct __acl_ext	i;
};

#define aprev		i.a_prev
#define anext		i.a_next
#define acurr		i.a_curr
#define aused		i.a_used
#define aprealloc	i.a_prealloc
#define aprealloc_end	i.a_prealloc_end

/* external ACL representation */
struct __acl {
	size_t			x_size;
	struct __acl_entry	x_entries[0];
};

extern int __acl_reorder_entry_obj_p(acl_entry_obj *acl_entry_obj_p) hidden;
extern int __acl_reorder_obj_p(acl_obj *acl_obj_p) hidden;

extern acl_obj *__acl_init_obj(int count) hidden;
extern acl_entry_obj *__acl_create_entry_obj(acl_obj *acl_obj_p) hidden;
extern void __acl_free_acl_obj(acl_obj *acl_obj_p) hidden;

extern char *__acl_to_any_text(acl_t acl, ssize_t *len_p,
			       const char *prefix, char separator,
			       const char *suffix, int options) hidden;
extern int __apply_mask_to_mode(mode_t *mode, acl_t acl) hidden;

#define FOREACH_ACL_ENTRY(entry_obj_p, acl_obj_p) \
	for( (entry_obj_p) = (acl_obj_p)->anext; \
	     (entry_obj_p) != (acl_entry_obj *)(acl_obj_p); \
	     (entry_obj_p) = (entry_obj_p)->enext )
