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