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
33static uint64_t zero_times[2];
34
35static int
36getxva_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 */
43int
44fop__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
72static int
73getxva_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
194out:
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 */
202int
203fop__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