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