#include <sys/types.h>
#include <sys/vnode.h>
#include <sys/debug.h>
#include <attr.h>
#include <libnvpair.h>
#include "vncache.h"
static uint64_t zero_times[2];
static int
getxva_parse_nvl(xvattr_t *xvap,
xoptattr_t *xoap, nvlist_t *nvl);
int
fop__getxvattr(vnode_t *vp, xvattr_t *xvap)
{
nvlist_t *nvl = NULL;
xoptattr_t *xoap = NULL;
int fd = vncache_getfd(vp);
int error;
if ((xoap = xva_getxoptattr(xvap)) == NULL) {
return (EINVAL);
}
error = fgetattr(fd, XATTR_VIEW_READWRITE, &nvl);
if (error == 0) {
error = getxva_parse_nvl(xvap, xoap, nvl);
nvlist_free(nvl);
nvl = NULL;
}
if (fgetattr(fd, XATTR_VIEW_READONLY, &nvl) == 0) {
(void) getxva_parse_nvl(xvap, xoap, nvl);
nvlist_free(nvl);
}
return (error);
}
static int
getxva_parse_nvl(xvattr_t *xvap,
xoptattr_t *xoap, nvlist_t *nvl)
{
nvpair_t *pair = NULL;
int error;
while ((pair = nvlist_next_nvpair(nvl, pair)) != NULL) {
data_type_t type;
f_attr_t attr;
boolean_t value = B_FALSE;
uint64_t *times = zero_times;
uint_t nelems = 2;
type = nvpair_type(pair);
attr = name_to_attr(nvpair_name(pair));
if (attr == F_ATTR_INVAL)
continue;
if (type != attr_to_data_type(attr) ||
(attr_to_xattr_view(attr) == XATTR_VIEW_READONLY))
continue;
if ((attr == F_OWNERSID || attr == F_GROUPSID))
continue;
switch (type) {
case DATA_TYPE_BOOLEAN_VALUE:
if (nvpair_value_boolean_value(pair, &value)) {
error = EINVAL;
goto out;
}
break;
case DATA_TYPE_UINT64_ARRAY:
if (nvpair_value_uint64_array(pair, ×, &nelems)) {
error = EINVAL;
goto out;
}
if (nelems < 2)
continue;
break;
case DATA_TYPE_NVLIST:
continue;
case DATA_TYPE_UINT8_ARRAY:
continue;
default:
error = EINVAL;
goto out;
}
switch (attr) {
case F_READONLY:
XVA_SET_RTN(xvap, XAT_READONLY);
xoap->xoa_readonly = value;
break;
case F_HIDDEN:
XVA_SET_RTN(xvap, XAT_HIDDEN);
xoap->xoa_hidden = value;
break;
case F_SYSTEM:
XVA_SET_RTN(xvap, XAT_SYSTEM);
xoap->xoa_system = value;
break;
case F_ARCHIVE:
XVA_SET_RTN(xvap, XAT_ARCHIVE);
xoap->xoa_archive = value;
break;
case F_CRTIME:
XVA_SET_RTN(xvap, XAT_CREATETIME);
xoap->xoa_createtime.tv_sec = times[0];
xoap->xoa_createtime.tv_nsec = times[1];
break;
case F_REPARSE:
XVA_SET_RTN(xvap, XAT_REPARSE);
xoap->xoa_reparse = value;
break;
case F_OFFLINE:
XVA_SET_RTN(xvap, XAT_OFFLINE);
xoap->xoa_offline = value;
break;
case F_SPARSE:
XVA_SET_RTN(xvap, XAT_SPARSE);
xoap->xoa_sparse = value;
break;
default:
break;
}
}
error = 0;
out:
return (error);
}
int
fop__setxvattr(vnode_t *vp, xvattr_t *xvap)
{
uint64_t times[2];
nvlist_t *nvl;
xoptattr_t *xoap;
int fd = vncache_getfd(vp);
int error;
if ((xoap = xva_getxoptattr(xvap)) == NULL)
return (EINVAL);
if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP))
return (ENOMEM);
if (XVA_ISSET_REQ(xvap, XAT_READONLY)) {
VERIFY(nvlist_add_boolean_value(nvl,
attr_to_name(F_READONLY),
xoap->xoa_readonly) == 0);
}
if (XVA_ISSET_REQ(xvap, XAT_HIDDEN)) {
VERIFY(nvlist_add_boolean_value(nvl,
attr_to_name(F_HIDDEN),
xoap->xoa_hidden) == 0);
}
if (XVA_ISSET_REQ(xvap, XAT_SYSTEM)) {
VERIFY(nvlist_add_boolean_value(nvl,
attr_to_name(F_SYSTEM),
xoap->xoa_system) == 0);
}
if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE)) {
VERIFY(nvlist_add_boolean_value(nvl,
attr_to_name(F_ARCHIVE),
xoap->xoa_archive) == 0);
}
if (XVA_ISSET_REQ(xvap, XAT_CREATETIME)) {
times[0] = xoap->xoa_createtime.tv_sec;
times[1] = xoap->xoa_createtime.tv_nsec;
VERIFY(nvlist_add_uint64_array(nvl,
attr_to_name(F_CRTIME),
times, 2) == 0);
}
if (XVA_ISSET_REQ(xvap, XAT_REPARSE)) {
VERIFY(nvlist_add_boolean_value(nvl,
attr_to_name(F_REPARSE),
xoap->xoa_reparse) == 0);
}
if (XVA_ISSET_REQ(xvap, XAT_OFFLINE)) {
VERIFY(nvlist_add_boolean_value(nvl,
attr_to_name(F_OFFLINE),
xoap->xoa_offline) == 0);
}
if (XVA_ISSET_REQ(xvap, XAT_SPARSE)) {
VERIFY(nvlist_add_boolean_value(nvl,
attr_to_name(F_SPARSE),
xoap->xoa_sparse) == 0);
}
error = fsetattr(fd, XATTR_VIEW_READWRITE, nvl);
nvlist_free(nvl);
return (error);
}