1*b819cea2SGordon Ross /* 2*b819cea2SGordon Ross * CDDL HEADER START 3*b819cea2SGordon Ross * 4*b819cea2SGordon Ross * The contents of this file are subject to the terms of the 5*b819cea2SGordon Ross * Common Development and Distribution License (the "License"). 6*b819cea2SGordon Ross * You may not use this file except in compliance with the License. 7*b819cea2SGordon Ross * 8*b819cea2SGordon Ross * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*b819cea2SGordon Ross * or http://www.opensolaris.org/os/licensing. 10*b819cea2SGordon Ross * See the License for the specific language governing permissions 11*b819cea2SGordon Ross * and limitations under the License. 12*b819cea2SGordon Ross * 13*b819cea2SGordon Ross * When distributing Covered Code, include this CDDL HEADER in each 14*b819cea2SGordon Ross * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*b819cea2SGordon Ross * If applicable, add the following below this CDDL HEADER, with the 16*b819cea2SGordon Ross * fields enclosed by brackets "[]" replaced with your own identifying 17*b819cea2SGordon Ross * information: Portions Copyright [yyyy] [name of copyright owner] 18*b819cea2SGordon Ross * 19*b819cea2SGordon Ross * CDDL HEADER END 20*b819cea2SGordon Ross */ 21*b819cea2SGordon Ross /* 22*b819cea2SGordon Ross * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23*b819cea2SGordon Ross * Copyright 2014 Nexenta Systems, Inc. All rights reserved. 24*b819cea2SGordon Ross */ 25*b819cea2SGordon Ross 26*b819cea2SGordon Ross #include <sys/types.h> 27*b819cea2SGordon Ross #include <sys/vnode.h> 28*b819cea2SGordon Ross #include <sys/debug.h> 29*b819cea2SGordon Ross 30*b819cea2SGordon Ross #include <attr.h> 31*b819cea2SGordon Ross #include <libnvpair.h> 32*b819cea2SGordon Ross 33*b819cea2SGordon Ross static uint64_t zero_times[2]; 34*b819cea2SGordon Ross 35*b819cea2SGordon Ross static int 36*b819cea2SGordon Ross getxva_parse_nvl(xvattr_t *xvap, 37*b819cea2SGordon Ross xoptattr_t *xoap, nvlist_t *nvl); 38*b819cea2SGordon Ross 39*b819cea2SGordon Ross /* 40*b819cea2SGordon Ross * See similar code to parse the nvlist in: 41*b819cea2SGordon Ross * uts/common/fs/xattr.c : xattr_file_write() 42*b819cea2SGordon Ross */ 43*b819cea2SGordon Ross int 44*b819cea2SGordon Ross fop__getxvattr(vnode_t *vp, xvattr_t *xvap) 45*b819cea2SGordon Ross { 46*b819cea2SGordon Ross nvlist_t *nvl = NULL; 47*b819cea2SGordon Ross xoptattr_t *xoap = NULL; 48*b819cea2SGordon Ross int error; 49*b819cea2SGordon Ross 50*b819cea2SGordon Ross if ((xoap = xva_getxoptattr(xvap)) == NULL) { 51*b819cea2SGordon Ross return (EINVAL); 52*b819cea2SGordon Ross } 53*b819cea2SGordon Ross 54*b819cea2SGordon Ross error = fgetattr(vp->v_fd, XATTR_VIEW_READWRITE, &nvl); 55*b819cea2SGordon Ross if (error == 0) { 56*b819cea2SGordon Ross error = getxva_parse_nvl(xvap, xoap, nvl); 57*b819cea2SGordon Ross nvlist_free(nvl); 58*b819cea2SGordon Ross nvl = NULL; 59*b819cea2SGordon Ross } 60*b819cea2SGordon Ross 61*b819cea2SGordon Ross /* 62*b819cea2SGordon Ross * Also get the readonly attrs, but don't fail. 63*b819cea2SGordon Ross */ 64*b819cea2SGordon Ross if (fgetattr(vp->v_fd, XATTR_VIEW_READONLY, &nvl) == 0) { 65*b819cea2SGordon Ross (void) getxva_parse_nvl(xvap, xoap, nvl); 66*b819cea2SGordon Ross nvlist_free(nvl); 67*b819cea2SGordon Ross } 68*b819cea2SGordon Ross 69*b819cea2SGordon Ross return (error); 70*b819cea2SGordon Ross } 71*b819cea2SGordon Ross 72*b819cea2SGordon Ross static int 73*b819cea2SGordon Ross getxva_parse_nvl(xvattr_t *xvap, 74*b819cea2SGordon Ross xoptattr_t *xoap, nvlist_t *nvl) 75*b819cea2SGordon Ross { 76*b819cea2SGordon Ross nvpair_t *pair = NULL; 77*b819cea2SGordon Ross int error; 78*b819cea2SGordon Ross 79*b819cea2SGordon Ross while (pair = nvlist_next_nvpair(nvl, pair)) { 80*b819cea2SGordon Ross data_type_t type; 81*b819cea2SGordon Ross f_attr_t attr; 82*b819cea2SGordon Ross boolean_t value = B_FALSE; 83*b819cea2SGordon Ross uint64_t *times = zero_times; 84*b819cea2SGordon Ross uint_t nelems = 2; 85*b819cea2SGordon Ross 86*b819cea2SGordon Ross /* 87*b819cea2SGordon Ross * Validate the name and type of each attribute. 88*b819cea2SGordon Ross * Log any unknown names and continue. This will 89*b819cea2SGordon Ross * help if additional attributes are added later. 90*b819cea2SGordon Ross */ 91*b819cea2SGordon Ross type = nvpair_type(pair); 92*b819cea2SGordon Ross attr = name_to_attr(nvpair_name(pair)); 93*b819cea2SGordon Ross if (attr == F_ATTR_INVAL) 94*b819cea2SGordon Ross continue; 95*b819cea2SGordon Ross 96*b819cea2SGordon Ross /* 97*b819cea2SGordon Ross * Verify nvlist type matches required type and view is OK 98*b819cea2SGordon Ross */ 99*b819cea2SGordon Ross 100*b819cea2SGordon Ross if (type != attr_to_data_type(attr) || 101*b819cea2SGordon Ross (attr_to_xattr_view(attr) == XATTR_VIEW_READONLY)) 102*b819cea2SGordon Ross continue; 103*b819cea2SGordon Ross 104*b819cea2SGordon Ross /* 105*b819cea2SGordon Ross * For OWNERSID/GROUPSID, just skip. 106*b819cea2SGordon Ross */ 107*b819cea2SGordon Ross if ((attr == F_OWNERSID || attr == F_GROUPSID)) 108*b819cea2SGordon Ross continue; 109*b819cea2SGordon Ross 110*b819cea2SGordon Ross /* 111*b819cea2SGordon Ross * Retrieve data from nvpair 112*b819cea2SGordon Ross */ 113*b819cea2SGordon Ross switch (type) { 114*b819cea2SGordon Ross case DATA_TYPE_BOOLEAN_VALUE: 115*b819cea2SGordon Ross if (nvpair_value_boolean_value(pair, &value)) { 116*b819cea2SGordon Ross error = EINVAL; 117*b819cea2SGordon Ross goto out; 118*b819cea2SGordon Ross } 119*b819cea2SGordon Ross break; 120*b819cea2SGordon Ross 121*b819cea2SGordon Ross case DATA_TYPE_UINT64_ARRAY: 122*b819cea2SGordon Ross if (nvpair_value_uint64_array(pair, ×, &nelems)) { 123*b819cea2SGordon Ross error = EINVAL; 124*b819cea2SGordon Ross goto out; 125*b819cea2SGordon Ross } 126*b819cea2SGordon Ross if (nelems < 2) 127*b819cea2SGordon Ross continue; 128*b819cea2SGordon Ross break; 129*b819cea2SGordon Ross 130*b819cea2SGordon Ross case DATA_TYPE_NVLIST: 131*b819cea2SGordon Ross continue; 132*b819cea2SGordon Ross 133*b819cea2SGordon Ross case DATA_TYPE_UINT8_ARRAY: 134*b819cea2SGordon Ross continue; 135*b819cea2SGordon Ross 136*b819cea2SGordon Ross default: 137*b819cea2SGordon Ross error = EINVAL; 138*b819cea2SGordon Ross goto out; 139*b819cea2SGordon Ross } 140*b819cea2SGordon Ross 141*b819cea2SGordon Ross switch (attr) { 142*b819cea2SGordon Ross /* 143*b819cea2SGordon Ross * If we have several similar optional attributes to 144*b819cea2SGordon Ross * process then we should do it all together here so that 145*b819cea2SGordon Ross * xoap and the requested bitmap can be set in one place. 146*b819cea2SGordon Ross */ 147*b819cea2SGordon Ross case F_READONLY: 148*b819cea2SGordon Ross XVA_SET_RTN(xvap, XAT_READONLY); 149*b819cea2SGordon Ross xoap->xoa_readonly = value; 150*b819cea2SGordon Ross break; 151*b819cea2SGordon Ross 152*b819cea2SGordon Ross case F_HIDDEN: 153*b819cea2SGordon Ross XVA_SET_RTN(xvap, XAT_HIDDEN); 154*b819cea2SGordon Ross xoap->xoa_hidden = value; 155*b819cea2SGordon Ross break; 156*b819cea2SGordon Ross 157*b819cea2SGordon Ross case F_SYSTEM: 158*b819cea2SGordon Ross XVA_SET_RTN(xvap, XAT_SYSTEM); 159*b819cea2SGordon Ross xoap->xoa_system = value; 160*b819cea2SGordon Ross break; 161*b819cea2SGordon Ross 162*b819cea2SGordon Ross case F_ARCHIVE: 163*b819cea2SGordon Ross XVA_SET_RTN(xvap, XAT_ARCHIVE); 164*b819cea2SGordon Ross xoap->xoa_archive = value; 165*b819cea2SGordon Ross break; 166*b819cea2SGordon Ross 167*b819cea2SGordon Ross case F_CRTIME: 168*b819cea2SGordon Ross XVA_SET_RTN(xvap, XAT_CREATETIME); 169*b819cea2SGordon Ross xoap->xoa_createtime.tv_sec = times[0]; 170*b819cea2SGordon Ross xoap->xoa_createtime.tv_nsec = times[1]; 171*b819cea2SGordon Ross break; 172*b819cea2SGordon Ross 173*b819cea2SGordon Ross case F_REPARSE: 174*b819cea2SGordon Ross XVA_SET_RTN(xvap, XAT_REPARSE); 175*b819cea2SGordon Ross xoap->xoa_reparse = value; 176*b819cea2SGordon Ross break; 177*b819cea2SGordon Ross 178*b819cea2SGordon Ross case F_OFFLINE: 179*b819cea2SGordon Ross XVA_SET_RTN(xvap, XAT_OFFLINE); 180*b819cea2SGordon Ross xoap->xoa_offline = value; 181*b819cea2SGordon Ross break; 182*b819cea2SGordon Ross 183*b819cea2SGordon Ross case F_SPARSE: 184*b819cea2SGordon Ross XVA_SET_RTN(xvap, XAT_SPARSE); 185*b819cea2SGordon Ross xoap->xoa_sparse = value; 186*b819cea2SGordon Ross break; 187*b819cea2SGordon Ross 188*b819cea2SGordon Ross default: 189*b819cea2SGordon Ross break; 190*b819cea2SGordon Ross } 191*b819cea2SGordon Ross } 192*b819cea2SGordon Ross error = 0; 193*b819cea2SGordon Ross 194*b819cea2SGordon Ross out: 195*b819cea2SGordon Ross return (error); 196*b819cea2SGordon Ross } 197*b819cea2SGordon Ross 198*b819cea2SGordon Ross /* 199*b819cea2SGordon Ross * See similar code to build the nvlist in: 200*b819cea2SGordon Ross * uts/common/fs/xattr.c : xattr_fill_nvlist() 201*b819cea2SGordon Ross */ 202*b819cea2SGordon Ross int 203*b819cea2SGordon Ross fop__setxvattr(vnode_t *vp, xvattr_t *xvap) 204*b819cea2SGordon Ross { 205*b819cea2SGordon Ross uint64_t times[2]; 206*b819cea2SGordon Ross nvlist_t *nvl; 207*b819cea2SGordon Ross int error; 208*b819cea2SGordon Ross xoptattr_t *xoap; /* Pointer to optional attributes */ 209*b819cea2SGordon Ross 210*b819cea2SGordon Ross if ((xoap = xva_getxoptattr(xvap)) == NULL) 211*b819cea2SGordon Ross return (EINVAL); 212*b819cea2SGordon Ross 213*b819cea2SGordon Ross if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP)) 214*b819cea2SGordon Ross return (ENOMEM); 215*b819cea2SGordon Ross 216*b819cea2SGordon Ross if (XVA_ISSET_REQ(xvap, XAT_READONLY)) { 217*b819cea2SGordon Ross VERIFY(nvlist_add_boolean_value(nvl, 218*b819cea2SGordon Ross attr_to_name(F_READONLY), 219*b819cea2SGordon Ross xoap->xoa_readonly) == 0); 220*b819cea2SGordon Ross } 221*b819cea2SGordon Ross 222*b819cea2SGordon Ross if (XVA_ISSET_REQ(xvap, XAT_HIDDEN)) { 223*b819cea2SGordon Ross VERIFY(nvlist_add_boolean_value(nvl, 224*b819cea2SGordon Ross attr_to_name(F_HIDDEN), 225*b819cea2SGordon Ross xoap->xoa_hidden) == 0); 226*b819cea2SGordon Ross } 227*b819cea2SGordon Ross 228*b819cea2SGordon Ross if (XVA_ISSET_REQ(xvap, XAT_SYSTEM)) { 229*b819cea2SGordon Ross VERIFY(nvlist_add_boolean_value(nvl, 230*b819cea2SGordon Ross attr_to_name(F_SYSTEM), 231*b819cea2SGordon Ross xoap->xoa_system) == 0); 232*b819cea2SGordon Ross } 233*b819cea2SGordon Ross 234*b819cea2SGordon Ross if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE)) { 235*b819cea2SGordon Ross VERIFY(nvlist_add_boolean_value(nvl, 236*b819cea2SGordon Ross attr_to_name(F_ARCHIVE), 237*b819cea2SGordon Ross xoap->xoa_archive) == 0); 238*b819cea2SGordon Ross } 239*b819cea2SGordon Ross 240*b819cea2SGordon Ross if (XVA_ISSET_REQ(xvap, XAT_CREATETIME)) { 241*b819cea2SGordon Ross times[0] = xoap->xoa_createtime.tv_sec; 242*b819cea2SGordon Ross times[1] = xoap->xoa_createtime.tv_nsec; 243*b819cea2SGordon Ross VERIFY(nvlist_add_uint64_array(nvl, 244*b819cea2SGordon Ross attr_to_name(F_CRTIME), 245*b819cea2SGordon Ross times, 2) == 0); 246*b819cea2SGordon Ross } 247*b819cea2SGordon Ross 248*b819cea2SGordon Ross if (XVA_ISSET_REQ(xvap, XAT_REPARSE)) { 249*b819cea2SGordon Ross VERIFY(nvlist_add_boolean_value(nvl, 250*b819cea2SGordon Ross attr_to_name(F_REPARSE), 251*b819cea2SGordon Ross xoap->xoa_reparse) == 0); 252*b819cea2SGordon Ross } 253*b819cea2SGordon Ross 254*b819cea2SGordon Ross if (XVA_ISSET_REQ(xvap, XAT_OFFLINE)) { 255*b819cea2SGordon Ross VERIFY(nvlist_add_boolean_value(nvl, 256*b819cea2SGordon Ross attr_to_name(F_OFFLINE), 257*b819cea2SGordon Ross xoap->xoa_offline) == 0); 258*b819cea2SGordon Ross } 259*b819cea2SGordon Ross 260*b819cea2SGordon Ross if (XVA_ISSET_REQ(xvap, XAT_SPARSE)) { 261*b819cea2SGordon Ross VERIFY(nvlist_add_boolean_value(nvl, 262*b819cea2SGordon Ross attr_to_name(F_SPARSE), 263*b819cea2SGordon Ross xoap->xoa_sparse) == 0); 264*b819cea2SGordon Ross } 265*b819cea2SGordon Ross 266*b819cea2SGordon Ross error = fsetattr(vp->v_fd, XATTR_VIEW_READWRITE, nvl); 267*b819cea2SGordon Ross 268*b819cea2SGordon Ross nvlist_free(nvl); 269*b819cea2SGordon Ross 270*b819cea2SGordon Ross return (error); 271*b819cea2SGordon Ross } 272