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