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