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
  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
  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
 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 }