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)) != 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, &times, &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