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
fop__getxvattr(vnode_t * vp,xvattr_t * xvap)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
getxva_parse_nvl(xvattr_t * xvap,xoptattr_t * xoap,nvlist_t * nvl)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
fop__setxvattr(vnode_t * vp,xvattr_t * xvap)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