/*
 * Copyright (c) 2022, Trond Myklebust <trond.myklebust@hammerspace.com>
 *
 * This code is free software; you can redistribute it and/or modify
 * it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE
 * version 2.1 as published by the Free Software Foundation.
 *
 * This code 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.
 */

#include <sys/types.h>
#include <config.h>
#ifdef HAVE_ATTR_XATTR_H
# include <attr/xattr.h>
#else
# ifdef HAVE_SYS_XATTR_H
#  include <sys/xattr.h>
# endif
#endif
#include <sys/stat.h>
#include "libacl_nfs4.h"

/* returns a newly-allocated struct nfs4_acl or NULL on error. */
static struct nfs4_acl *nfs4_getacl_byname(const char *path,
					   const char *xattr_name,
					   enum acl_type type)
{
	struct nfs4_acl *acl;
	struct stat st;
	void *buf;
	ssize_t ret;
	u32 iflags = NFS4_ACL_ISFILE;

	if (path == NULL || *path == 0) {
		errno = EFAULT;
		return NULL;
	}

	ret = stat(path, &st);
	if (ret == -1)
		goto err;

	if (S_ISDIR(st.st_mode))
		iflags = NFS4_ACL_ISDIR;

	/* find necessary buffer size */
	ret = getxattr(path, xattr_name, NULL, 0);
	if (ret == -1)
		goto err;

	buf = malloc(ret);
	if (!buf)
		goto err;

	/* reconstruct the ACL */
	ret = getxattr(path, xattr_name, buf, ret);
	if (ret == -1)
		goto err_free;

	acl = acl_nfs41_xattr_load(buf, ret, iflags, type);

	free(buf);
	return acl;
err_free:
	free(buf);
err:
	return NULL;
}

struct nfs4_acl *nfs4_getacl(const char *path)
{
	return nfs4_getacl_byname(path, ACL_NFS4_XATTR, ACL_TYPE_ACL);
}
struct nfs4_acl *nfs4_getdacl(const char *path)
{
	return nfs4_getacl_byname(path, DACL_NFS4_XATTR, ACL_TYPE_DACL);
}
struct nfs4_acl *nfs4_getsacl(const char *path)
{
	return nfs4_getacl_byname(path, SACL_NFS4_XATTR, ACL_TYPE_SACL);
}
