1*da6c28aaSamw /* 2*da6c28aaSamw * CDDL HEADER START 3*da6c28aaSamw * 4*da6c28aaSamw * The contents of this file are subject to the terms of the 5*da6c28aaSamw * Common Development and Distribution License (the "License"). 6*da6c28aaSamw * You may not use this file except in compliance with the License. 7*da6c28aaSamw * 8*da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*da6c28aaSamw * or http://www.opensolaris.org/os/licensing. 10*da6c28aaSamw * See the License for the specific language governing permissions 11*da6c28aaSamw * and limitations under the License. 12*da6c28aaSamw * 13*da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each 14*da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the 16*da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying 17*da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner] 18*da6c28aaSamw * 19*da6c28aaSamw * CDDL HEADER END 20*da6c28aaSamw */ 21*da6c28aaSamw /* 22*da6c28aaSamw * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23*da6c28aaSamw * Use is subject to license terms. 24*da6c28aaSamw */ 25*da6c28aaSamw 26*da6c28aaSamw #pragma ident "%Z%%M% %I% %E% SMI" 27*da6c28aaSamw 28*da6c28aaSamw #include <sys/types.h> 29*da6c28aaSamw #include <sys/stat.h> 30*da6c28aaSamw #include <sys/uio.h> 31*da6c28aaSamw #include <sys/statvfs.h> 32*da6c28aaSamw #include <sys/vnode.h> 33*da6c28aaSamw #include <sys/thread.h> 34*da6c28aaSamw #include <sys/pathname.h> 35*da6c28aaSamw #include <sys/cred.h> 36*da6c28aaSamw #include <sys/extdirent.h> 37*da6c28aaSamw #include <acl/acl_common.h> 38*da6c28aaSamw #include <smbsrv/smb_vops.h> 39*da6c28aaSamw #include <smbsrv/string.h> 40*da6c28aaSamw #include <smbsrv/lmshare.h> 41*da6c28aaSamw #include <smbsrv/smbtrans.h> 42*da6c28aaSamw #include <smbsrv/smb_incl.h> 43*da6c28aaSamw #include <smbsrv/smb_fsops.h> 44*da6c28aaSamw 45*da6c28aaSamw static int 46*da6c28aaSamw smb_vop_readdir_readpage(vnode_t *vp, void *buf, uint32_t offset, int *count, 47*da6c28aaSamw cred_t *cr, caller_context_t *ct, int flags); 48*da6c28aaSamw 49*da6c28aaSamw static int 50*da6c28aaSamw smb_vop_readdir_entry(vnode_t *dvp, uint32_t *cookiep, char *name, int *namelen, 51*da6c28aaSamw ino64_t *inop, vnode_t **vpp, char *od_name, int flags, cred_t *cr, 52*da6c28aaSamw caller_context_t *ct, char *dirbuf, int num_bytes); 53*da6c28aaSamw 54*da6c28aaSamw static int 55*da6c28aaSamw smb_vop_getdents_entries(smb_node_t *dir_snode, uint32_t *cookiep, 56*da6c28aaSamw int32_t *dircountp, char *arg, uint32_t flags, struct smb_request *sr, 57*da6c28aaSamw cred_t *cr, caller_context_t *ct, char *dirbuf, int *maxentries, 58*da6c28aaSamw int num_bytes, char *); 59*da6c28aaSamw 60*da6c28aaSamw extern int 61*da6c28aaSamw smb_gather_dents_info(char *args, ino_t fileid, int namelen, 62*da6c28aaSamw char *name, uint32_t cookie, int32_t *countp, 63*da6c28aaSamw smb_attr_t *attr, struct smb_node *snode, 64*da6c28aaSamw char *shortname, char *name83); 65*da6c28aaSamw 66*da6c28aaSamw static void 67*da6c28aaSamw smb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp); 68*da6c28aaSamw 69*da6c28aaSamw #define SMB_AT_MAX 16 70*da6c28aaSamw static uint_t smb_attrmap[SMB_AT_MAX] = { 71*da6c28aaSamw 0, 72*da6c28aaSamw AT_TYPE, 73*da6c28aaSamw AT_MODE, 74*da6c28aaSamw AT_UID, 75*da6c28aaSamw AT_GID, 76*da6c28aaSamw AT_FSID, 77*da6c28aaSamw AT_NODEID, 78*da6c28aaSamw AT_NLINK, 79*da6c28aaSamw AT_SIZE, 80*da6c28aaSamw AT_ATIME, 81*da6c28aaSamw AT_MTIME, 82*da6c28aaSamw AT_CTIME, 83*da6c28aaSamw AT_RDEV, 84*da6c28aaSamw AT_BLKSIZE, 85*da6c28aaSamw AT_NBLOCKS, 86*da6c28aaSamw AT_SEQ 87*da6c28aaSamw }; 88*da6c28aaSamw 89*da6c28aaSamw int 90*da6c28aaSamw smb_vop_open(vnode_t **vpp, int mode, cred_t *cred, caller_context_t *ct) 91*da6c28aaSamw { 92*da6c28aaSamw return (VOP_OPEN(vpp, mode, cred, ct)); 93*da6c28aaSamw } 94*da6c28aaSamw 95*da6c28aaSamw int 96*da6c28aaSamw smb_vop_close(vnode_t *vp, int mode, cred_t *cred, caller_context_t *ct) 97*da6c28aaSamw { 98*da6c28aaSamw return (VOP_CLOSE(vp, mode, 1, (offset_t)0, cred, ct)); 99*da6c28aaSamw } 100*da6c28aaSamw 101*da6c28aaSamw /* 102*da6c28aaSamw * The smb_vop_* functions have minimal knowledge of CIFS semantics and 103*da6c28aaSamw * serve as an interface to the VFS layer. 104*da6c28aaSamw * 105*da6c28aaSamw * Only smb_fsop_* layer functions should call smb_vop_* layer functions. 106*da6c28aaSamw * (Higher-level CIFS service code should never skip the smb_fsop_* layer 107*da6c28aaSamw * to call smb_vop_* layer functions directly.) 108*da6c28aaSamw */ 109*da6c28aaSamw 110*da6c28aaSamw /* 111*da6c28aaSamw * XXX - Extended attributes support in the file system assumed. 112*da6c28aaSamw * This is needed for full NT Streams functionality. 113*da6c28aaSamw */ 114*da6c28aaSamw 115*da6c28aaSamw int 116*da6c28aaSamw smb_vop_read(vnode_t *vp, uio_t *uiop, cred_t *cr, caller_context_t *ct) 117*da6c28aaSamw { 118*da6c28aaSamw int error; 119*da6c28aaSamw 120*da6c28aaSamw (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL); 121*da6c28aaSamw error = VOP_READ(vp, uiop, 0, cr, ct); 122*da6c28aaSamw VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 123*da6c28aaSamw return (error); 124*da6c28aaSamw } 125*da6c28aaSamw 126*da6c28aaSamw int 127*da6c28aaSamw smb_vop_write(vnode_t *vp, uio_t *uiop, uint32_t *flag, uint32_t *lcount, 128*da6c28aaSamw cred_t *cr, caller_context_t *ct) 129*da6c28aaSamw { 130*da6c28aaSamw int error; 131*da6c28aaSamw int ioflag = 0; 132*da6c28aaSamw 133*da6c28aaSamw *lcount = uiop->uio_resid; 134*da6c28aaSamw 135*da6c28aaSamw if (*flag == FSSTAB_FILE_SYNC) 136*da6c28aaSamw ioflag = FSYNC; 137*da6c28aaSamw 138*da6c28aaSamw uiop->uio_llimit = MAXOFFSET_T; 139*da6c28aaSamw 140*da6c28aaSamw (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); 141*da6c28aaSamw error = VOP_WRITE(vp, uiop, ioflag, cr, ct); 142*da6c28aaSamw VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 143*da6c28aaSamw 144*da6c28aaSamw *lcount -= uiop->uio_resid; 145*da6c28aaSamw 146*da6c28aaSamw return (error); 147*da6c28aaSamw } 148*da6c28aaSamw 149*da6c28aaSamw /* 150*da6c28aaSamw * smb_vop_getattr() 151*da6c28aaSamw * 152*da6c28aaSamw * smb_fsop_getattr()/smb_vop_getattr() should always be called from the CIFS 153*da6c28aaSamw * service (instead of calling VOP_GETATTR directly) to retrieve attributes 154*da6c28aaSamw * due to special processing needed for streams files. 155*da6c28aaSamw * 156*da6c28aaSamw * All attributes are retrieved. 157*da6c28aaSamw * 158*da6c28aaSamw * A named stream's attributes (as far as CIFS is concerned) are those of the 159*da6c28aaSamw * unnamed (i.e. data) stream (minus the size attribute), and the size of the 160*da6c28aaSamw * named stream. Though the file system may store attributes other than size 161*da6c28aaSamw * with the named stream, these should not be used by CIFS for any purpose. 162*da6c28aaSamw * 163*da6c28aaSamw * When vp denotes a named stream, then unnamed_vp should be passed in (denoting 164*da6c28aaSamw * the corresponding unnamed stream). 165*da6c28aaSamw */ 166*da6c28aaSamw 167*da6c28aaSamw int 168*da6c28aaSamw smb_vop_getattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *ret_attr, 169*da6c28aaSamw int flags, cred_t *cr, caller_context_t *ct) 170*da6c28aaSamw { 171*da6c28aaSamw int error; 172*da6c28aaSamw vnode_t *use_vp; 173*da6c28aaSamw smb_attr_t tmp_attr; 174*da6c28aaSamw xvattr_t tmp_xvattr; 175*da6c28aaSamw xoptattr_t *xoap = NULL; 176*da6c28aaSamw 177*da6c28aaSamw if (unnamed_vp) 178*da6c28aaSamw use_vp = unnamed_vp; 179*da6c28aaSamw else 180*da6c28aaSamw use_vp = vp; 181*da6c28aaSamw 182*da6c28aaSamw if (vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) { 183*da6c28aaSamw xva_init(&tmp_xvattr); 184*da6c28aaSamw xoap = xva_getxoptattr(&tmp_xvattr); 185*da6c28aaSamw 186*da6c28aaSamw ASSERT(xoap); 187*da6c28aaSamw 188*da6c28aaSamw smb_sa_to_va_mask(ret_attr->sa_mask, 189*da6c28aaSamw &tmp_xvattr.xva_vattr.va_mask); 190*da6c28aaSamw 191*da6c28aaSamw XVA_SET_REQ(&tmp_xvattr, XAT_READONLY); 192*da6c28aaSamw XVA_SET_REQ(&tmp_xvattr, XAT_HIDDEN); 193*da6c28aaSamw XVA_SET_REQ(&tmp_xvattr, XAT_SYSTEM); 194*da6c28aaSamw XVA_SET_REQ(&tmp_xvattr, XAT_ARCHIVE); 195*da6c28aaSamw XVA_SET_REQ(&tmp_xvattr, XAT_CREATETIME); 196*da6c28aaSamw 197*da6c28aaSamw if ((error = VOP_GETATTR(use_vp, (vattr_t *)&tmp_xvattr, flags, 198*da6c28aaSamw cr, ct)) != 0) 199*da6c28aaSamw return (error); 200*da6c28aaSamw 201*da6c28aaSamw ret_attr->sa_vattr = tmp_xvattr.xva_vattr; 202*da6c28aaSamw 203*da6c28aaSamw /* 204*da6c28aaSamw * Copy special attributes to ret_attr parameter 205*da6c28aaSamw */ 206*da6c28aaSamw 207*da6c28aaSamw ret_attr->sa_dosattr = 0; 208*da6c28aaSamw 209*da6c28aaSamw ASSERT(tmp_xvattr.xva_vattr.va_mask & AT_XVATTR); 210*da6c28aaSamw 211*da6c28aaSamw xoap = xva_getxoptattr(&tmp_xvattr); 212*da6c28aaSamw ASSERT(xoap); 213*da6c28aaSamw 214*da6c28aaSamw if (XVA_ISSET_RTN(&tmp_xvattr, XAT_READONLY)) { 215*da6c28aaSamw if (xoap->xoa_readonly) 216*da6c28aaSamw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_READONLY; 217*da6c28aaSamw } 218*da6c28aaSamw 219*da6c28aaSamw if (XVA_ISSET_RTN(&tmp_xvattr, XAT_HIDDEN)) { 220*da6c28aaSamw if (xoap->xoa_hidden) 221*da6c28aaSamw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_HIDDEN; 222*da6c28aaSamw } 223*da6c28aaSamw 224*da6c28aaSamw if (XVA_ISSET_RTN(&tmp_xvattr, XAT_SYSTEM)) { 225*da6c28aaSamw if (xoap->xoa_system) 226*da6c28aaSamw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_SYSTEM; 227*da6c28aaSamw } 228*da6c28aaSamw 229*da6c28aaSamw if (XVA_ISSET_RTN(&tmp_xvattr, XAT_ARCHIVE)) { 230*da6c28aaSamw if (xoap->xoa_archive) 231*da6c28aaSamw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_ARCHIVE; 232*da6c28aaSamw } 233*da6c28aaSamw 234*da6c28aaSamw ret_attr->sa_crtime = xoap->xoa_createtime; 235*da6c28aaSamw 236*da6c28aaSamw if (unnamed_vp && (ret_attr->sa_mask & SMB_AT_SIZE)) { 237*da6c28aaSamw /* 238*da6c28aaSamw * Retrieve stream size attribute into temporary 239*da6c28aaSamw * structure, in case the underlying file system 240*da6c28aaSamw * returns attributes other than the size (we do not 241*da6c28aaSamw * want to have ret_attr's other fields get 242*da6c28aaSamw * overwritten). 243*da6c28aaSamw * 244*da6c28aaSamw * Note that vp is used here, and not use_vp. 245*da6c28aaSamw * Also, only AT_SIZE is needed. 246*da6c28aaSamw */ 247*da6c28aaSamw 248*da6c28aaSamw tmp_xvattr.xva_vattr.va_mask = AT_SIZE; 249*da6c28aaSamw 250*da6c28aaSamw if ((error = VOP_GETATTR(vp, (vattr_t *)&tmp_xvattr, 251*da6c28aaSamw flags, cr, ct)) != 0) 252*da6c28aaSamw return (error); 253*da6c28aaSamw 254*da6c28aaSamw ret_attr->sa_vattr.va_size = 255*da6c28aaSamw tmp_xvattr.xva_vattr.va_size; 256*da6c28aaSamw 257*da6c28aaSamw } 258*da6c28aaSamw 259*da6c28aaSamw if (ret_attr->sa_vattr.va_type == VDIR) { 260*da6c28aaSamw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY; 261*da6c28aaSamw } 262*da6c28aaSamw 263*da6c28aaSamw return (error); 264*da6c28aaSamw } 265*da6c28aaSamw 266*da6c28aaSamw /* 267*da6c28aaSamw * Support for file systems without VFSFT_XVATTR 268*da6c28aaSamw */ 269*da6c28aaSamw 270*da6c28aaSamw smb_sa_to_va_mask(ret_attr->sa_mask, 271*da6c28aaSamw &ret_attr->sa_vattr.va_mask); 272*da6c28aaSamw 273*da6c28aaSamw error = VOP_GETATTR(use_vp, &ret_attr->sa_vattr, flags, cr, ct); 274*da6c28aaSamw 275*da6c28aaSamw if (error != 0) 276*da6c28aaSamw return (error); 277*da6c28aaSamw 278*da6c28aaSamw /* 279*da6c28aaSamw * "Fake" DOS attributes and create time, filesystem doesn't support 280*da6c28aaSamw * them. 281*da6c28aaSamw */ 282*da6c28aaSamw 283*da6c28aaSamw ret_attr->sa_dosattr = 0; 284*da6c28aaSamw ret_attr->sa_crtime = ret_attr->sa_vattr.va_ctime; 285*da6c28aaSamw 286*da6c28aaSamw if (unnamed_vp && (ret_attr->sa_mask & SMB_AT_SIZE)) { 287*da6c28aaSamw /* 288*da6c28aaSamw * Retrieve stream size attribute into temporary structure, 289*da6c28aaSamw * in case the underlying file system returns attributes 290*da6c28aaSamw * other than the size (we do not want to have ret_attr's 291*da6c28aaSamw * other fields get overwritten). 292*da6c28aaSamw * 293*da6c28aaSamw * Note that vp is used here, and not use_vp. 294*da6c28aaSamw * Also, only AT_SIZE is needed. 295*da6c28aaSamw */ 296*da6c28aaSamw 297*da6c28aaSamw tmp_attr.sa_vattr.va_mask = AT_SIZE; 298*da6c28aaSamw error = VOP_GETATTR(vp, &tmp_attr.sa_vattr, flags, cr, ct); 299*da6c28aaSamw 300*da6c28aaSamw if (error != 0) 301*da6c28aaSamw return (error); 302*da6c28aaSamw 303*da6c28aaSamw 304*da6c28aaSamw ret_attr->sa_vattr.va_size = tmp_attr.sa_vattr.va_size; 305*da6c28aaSamw } 306*da6c28aaSamw 307*da6c28aaSamw if (ret_attr->sa_vattr.va_type == VDIR) { 308*da6c28aaSamw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY; 309*da6c28aaSamw } 310*da6c28aaSamw 311*da6c28aaSamw return (error); 312*da6c28aaSamw } 313*da6c28aaSamw 314*da6c28aaSamw /* 315*da6c28aaSamw * smb_vop_setattr() 316*da6c28aaSamw * 317*da6c28aaSamw * smb_fsop_setattr()/smb_vop_setattr() should always be called from the CIFS 318*da6c28aaSamw * service to set attributes due to special processing for streams files. 319*da6c28aaSamw * 320*da6c28aaSamw * When smb_vop_setattr() is called on a named stream file, all indicated 321*da6c28aaSamw * attributes except the size are set on the unnamed stream file. The size 322*da6c28aaSamw * (if indicated) is set on the named stream file. 323*da6c28aaSamw */ 324*da6c28aaSamw 325*da6c28aaSamw int 326*da6c28aaSamw smb_vop_setattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *set_attr, 327*da6c28aaSamw int flags, cred_t *cr, caller_context_t *ct) 328*da6c28aaSamw { 329*da6c28aaSamw int error = 0; 330*da6c28aaSamw int at_size = 0; 331*da6c28aaSamw vnode_t *use_vp; 332*da6c28aaSamw xvattr_t tmp_xvattr; 333*da6c28aaSamw xoptattr_t *xoap = NULL; 334*da6c28aaSamw uint_t xva_mask; 335*da6c28aaSamw 336*da6c28aaSamw if (unnamed_vp) { 337*da6c28aaSamw use_vp = unnamed_vp; 338*da6c28aaSamw if (set_attr->sa_mask & SMB_AT_SIZE) { 339*da6c28aaSamw at_size = 1; 340*da6c28aaSamw set_attr->sa_mask &= ~SMB_AT_SIZE; 341*da6c28aaSamw } 342*da6c28aaSamw } else { 343*da6c28aaSamw use_vp = vp; 344*da6c28aaSamw } 345*da6c28aaSamw 346*da6c28aaSamw /* 347*da6c28aaSamw * The caller should not be setting sa_vattr.va_mask, 348*da6c28aaSamw * but rather sa_mask. 349*da6c28aaSamw */ 350*da6c28aaSamw 351*da6c28aaSamw set_attr->sa_vattr.va_mask = 0; 352*da6c28aaSamw 353*da6c28aaSamw if (vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) { 354*da6c28aaSamw /* 355*da6c28aaSamw * Initialize xvattr, including bzero 356*da6c28aaSamw */ 357*da6c28aaSamw xva_init(&tmp_xvattr); 358*da6c28aaSamw xoap = xva_getxoptattr(&tmp_xvattr); 359*da6c28aaSamw 360*da6c28aaSamw ASSERT(xoap); 361*da6c28aaSamw 362*da6c28aaSamw /* 363*da6c28aaSamw * Copy caller-specified classic attributes to tmp_xvattr. 364*da6c28aaSamw * First save tmp_xvattr's mask (set in xva_init()). 365*da6c28aaSamw * This is |'d in later. 366*da6c28aaSamw */ 367*da6c28aaSamw 368*da6c28aaSamw xva_mask = tmp_xvattr.xva_vattr.va_mask; 369*da6c28aaSamw tmp_xvattr.xva_vattr = set_attr->sa_vattr; 370*da6c28aaSamw 371*da6c28aaSamw smb_sa_to_va_mask(set_attr->sa_mask, 372*da6c28aaSamw &tmp_xvattr.xva_vattr.va_mask); 373*da6c28aaSamw 374*da6c28aaSamw /* 375*da6c28aaSamw * "|" in the original xva_mask. 376*da6c28aaSamw */ 377*da6c28aaSamw 378*da6c28aaSamw tmp_xvattr.xva_vattr.va_mask |= xva_mask; 379*da6c28aaSamw 380*da6c28aaSamw if (set_attr->sa_mask & SMB_AT_DOSATTR) { 381*da6c28aaSamw XVA_SET_REQ(&tmp_xvattr, XAT_ARCHIVE); 382*da6c28aaSamw XVA_SET_REQ(&tmp_xvattr, XAT_SYSTEM); 383*da6c28aaSamw XVA_SET_REQ(&tmp_xvattr, XAT_READONLY); 384*da6c28aaSamw XVA_SET_REQ(&tmp_xvattr, XAT_HIDDEN); 385*da6c28aaSamw 386*da6c28aaSamw /* 387*da6c28aaSamw * set_attr->sa_dosattr: If a given bit is not set, 388*da6c28aaSamw * that indicates that the corresponding field needs 389*da6c28aaSamw * to be updated with a "0" value. This is done 390*da6c28aaSamw * implicitly as the xoap->xoa_* fields were bzero'd. 391*da6c28aaSamw */ 392*da6c28aaSamw 393*da6c28aaSamw if (set_attr->sa_dosattr & FILE_ATTRIBUTE_ARCHIVE) 394*da6c28aaSamw xoap->xoa_archive = 1; 395*da6c28aaSamw 396*da6c28aaSamw if (set_attr->sa_dosattr & FILE_ATTRIBUTE_SYSTEM) 397*da6c28aaSamw xoap->xoa_system = 1; 398*da6c28aaSamw 399*da6c28aaSamw if (set_attr->sa_dosattr & FILE_ATTRIBUTE_READONLY) 400*da6c28aaSamw xoap->xoa_readonly = 1; 401*da6c28aaSamw 402*da6c28aaSamw if (set_attr->sa_dosattr & FILE_ATTRIBUTE_HIDDEN) 403*da6c28aaSamw xoap->xoa_hidden = 1; 404*da6c28aaSamw } 405*da6c28aaSamw 406*da6c28aaSamw if (set_attr->sa_mask & SMB_AT_CRTIME) { 407*da6c28aaSamw XVA_SET_REQ(&tmp_xvattr, XAT_CREATETIME); 408*da6c28aaSamw xoap->xoa_createtime = set_attr->sa_crtime; 409*da6c28aaSamw } 410*da6c28aaSamw 411*da6c28aaSamw if ((error = VOP_SETATTR(use_vp, (vattr_t *)&tmp_xvattr, flags, 412*da6c28aaSamw cr, ct)) != 0) 413*da6c28aaSamw return (error); 414*da6c28aaSamw 415*da6c28aaSamw /* 416*da6c28aaSamw * If the size of the stream needs to be set, set it on 417*da6c28aaSamw * the stream file directly. (All other indicated attributes 418*da6c28aaSamw * are set on the stream's unnamed stream, above.) 419*da6c28aaSamw */ 420*da6c28aaSamw 421*da6c28aaSamw if (at_size) { 422*da6c28aaSamw /* 423*da6c28aaSamw * set_attr->sa_vattr.va_size already contains the 424*da6c28aaSamw * size as set by the caller 425*da6c28aaSamw * 426*da6c28aaSamw * Note that vp is used here, and not use_vp. 427*da6c28aaSamw * Also, only AT_SIZE is needed. 428*da6c28aaSamw */ 429*da6c28aaSamw 430*da6c28aaSamw set_attr->sa_vattr.va_mask = AT_SIZE; 431*da6c28aaSamw error = VOP_SETATTR(vp, &set_attr->sa_vattr, flags, 432*da6c28aaSamw cr, ct); 433*da6c28aaSamw } 434*da6c28aaSamw 435*da6c28aaSamw return (error); 436*da6c28aaSamw } 437*da6c28aaSamw 438*da6c28aaSamw /* 439*da6c28aaSamw * Support for file systems without VFSFT_XVATTR 440*da6c28aaSamw */ 441*da6c28aaSamw 442*da6c28aaSamw smb_sa_to_va_mask(set_attr->sa_mask, &set_attr->sa_vattr.va_mask); 443*da6c28aaSamw 444*da6c28aaSamw /* 445*da6c28aaSamw * set_attr->sa_vattr already contains new values 446*da6c28aaSamw * as set by the caller 447*da6c28aaSamw */ 448*da6c28aaSamw 449*da6c28aaSamw error = VOP_SETATTR(use_vp, &set_attr->sa_vattr, flags, cr, ct); 450*da6c28aaSamw 451*da6c28aaSamw if (error != 0) 452*da6c28aaSamw return (error); 453*da6c28aaSamw 454*da6c28aaSamw if (at_size) { 455*da6c28aaSamw /* 456*da6c28aaSamw * set_attr->sa_vattr.va_size already contains the 457*da6c28aaSamw * size as set by the caller 458*da6c28aaSamw * 459*da6c28aaSamw * Note that vp is used here, and not use_vp. 460*da6c28aaSamw * Also, only AT_SIZE is needed. 461*da6c28aaSamw */ 462*da6c28aaSamw 463*da6c28aaSamw set_attr->sa_vattr.va_mask = AT_SIZE; 464*da6c28aaSamw error = VOP_SETATTR(vp, &set_attr->sa_vattr, flags, cr, ct); 465*da6c28aaSamw } 466*da6c28aaSamw 467*da6c28aaSamw return (error); 468*da6c28aaSamw } 469*da6c28aaSamw 470*da6c28aaSamw /* 471*da6c28aaSamw * smb_vop_access 472*da6c28aaSamw * 473*da6c28aaSamw * This is a wrapper round VOP_ACCESS. VOP_ACCESS checks the given mode 474*da6c28aaSamw * against file's ACL or Unix permissions. CIFS on the other hand needs to 475*da6c28aaSamw * know if the requested operation can succeed for the given object, this 476*da6c28aaSamw * requires more checks in case of DELETE bit since permissions on the parent 477*da6c28aaSamw * directory are important as well. Based on Windows rules if parent's ACL 478*da6c28aaSamw * grant FILE_DELETE_CHILD a file can be delete regardless of the file's 479*da6c28aaSamw * permissions. 480*da6c28aaSamw */ 481*da6c28aaSamw int 482*da6c28aaSamw smb_vop_access(vnode_t *vp, int mode, int flags, vnode_t *dir_vp, cred_t *cr) 483*da6c28aaSamw { 484*da6c28aaSamw int error = 0; 485*da6c28aaSamw 486*da6c28aaSamw if (mode == 0) 487*da6c28aaSamw return (0); 488*da6c28aaSamw 489*da6c28aaSamw if ((flags == V_ACE_MASK) && (mode & ACE_DELETE)) { 490*da6c28aaSamw if (dir_vp) { 491*da6c28aaSamw error = VOP_ACCESS(dir_vp, ACE_DELETE_CHILD, flags, 492*da6c28aaSamw cr, NULL); 493*da6c28aaSamw 494*da6c28aaSamw if (error == 0) 495*da6c28aaSamw mode &= ~ACE_DELETE; 496*da6c28aaSamw } 497*da6c28aaSamw } 498*da6c28aaSamw 499*da6c28aaSamw if (mode) { 500*da6c28aaSamw error = VOP_ACCESS(vp, mode, flags, cr, NULL); 501*da6c28aaSamw } 502*da6c28aaSamw 503*da6c28aaSamw return (error); 504*da6c28aaSamw } 505*da6c28aaSamw 506*da6c28aaSamw /* 507*da6c28aaSamw * smb_vop_lookup 508*da6c28aaSamw * 509*da6c28aaSamw * dvp: directory vnode (in) 510*da6c28aaSamw * name: name of file to be looked up (in) 511*da6c28aaSamw * vpp: looked-up vnode (out) 512*da6c28aaSamw * od_name: on-disk name of file (out). 513*da6c28aaSamw * This parameter is optional. If a pointer is passed in, it 514*da6c28aaSamw * must be allocated with MAXNAMELEN bytes 515*da6c28aaSamw * rootvp: vnode of the tree root (in) 516*da6c28aaSamw * This parameter is always passed in non-NULL except at the time 517*da6c28aaSamw * of share set up. 518*da6c28aaSamw */ 519*da6c28aaSamw 520*da6c28aaSamw int 521*da6c28aaSamw smb_vop_lookup(vnode_t *dvp, char *name, vnode_t **vpp, char *od_name, 522*da6c28aaSamw int flags, vnode_t *rootvp, cred_t *cr, caller_context_t *ct) 523*da6c28aaSamw { 524*da6c28aaSamw int error = 0; 525*da6c28aaSamw int option_flags = 0; 526*da6c28aaSamw pathname_t rpn; 527*da6c28aaSamw 528*da6c28aaSamw if (*name == '\0') 529*da6c28aaSamw return (EINVAL); 530*da6c28aaSamw 531*da6c28aaSamw ASSERT(vpp); 532*da6c28aaSamw *vpp = NULL; 533*da6c28aaSamw 534*da6c28aaSamw if ((name[0] == '.') && (name[1] == '.') && (name[2] == 0)) { 535*da6c28aaSamw if (rootvp && (dvp == rootvp)) { 536*da6c28aaSamw VN_HOLD(dvp); 537*da6c28aaSamw *vpp = dvp; 538*da6c28aaSamw return (0); 539*da6c28aaSamw } 540*da6c28aaSamw 541*da6c28aaSamw if (dvp->v_flag & VROOT) { 542*da6c28aaSamw vfs_t *vfsp; 543*da6c28aaSamw vnode_t *cvp = dvp; 544*da6c28aaSamw 545*da6c28aaSamw /* 546*da6c28aaSamw * Set dvp and check for races with forced unmount 547*da6c28aaSamw * (see lookuppnvp()) 548*da6c28aaSamw */ 549*da6c28aaSamw 550*da6c28aaSamw vfsp = cvp->v_vfsp; 551*da6c28aaSamw vfs_rlock_wait(vfsp); 552*da6c28aaSamw if (((dvp = cvp->v_vfsp->vfs_vnodecovered) == NULL) || 553*da6c28aaSamw (cvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)) { 554*da6c28aaSamw vfs_unlock(vfsp); 555*da6c28aaSamw return (EIO); 556*da6c28aaSamw } 557*da6c28aaSamw vfs_unlock(vfsp); 558*da6c28aaSamw } 559*da6c28aaSamw } 560*da6c28aaSamw 561*da6c28aaSamw 562*da6c28aaSamw 563*da6c28aaSamw if (flags & SMB_IGNORE_CASE) 564*da6c28aaSamw option_flags = FIGNORECASE; 565*da6c28aaSamw 566*da6c28aaSamw pn_alloc(&rpn); 567*da6c28aaSamw 568*da6c28aaSamw error = VOP_LOOKUP(dvp, name, vpp, NULL, option_flags, NULL, cr, 569*da6c28aaSamw ct, NULL, &rpn); 570*da6c28aaSamw 571*da6c28aaSamw if ((error == 0) && od_name) { 572*da6c28aaSamw bzero(od_name, MAXNAMELEN); 573*da6c28aaSamw if (option_flags == FIGNORECASE) 574*da6c28aaSamw (void) strlcpy(od_name, rpn.pn_buf, MAXNAMELEN); 575*da6c28aaSamw else 576*da6c28aaSamw (void) strlcpy(od_name, name, MAXNAMELEN); 577*da6c28aaSamw } 578*da6c28aaSamw 579*da6c28aaSamw pn_free(&rpn); 580*da6c28aaSamw return (error); 581*da6c28aaSamw } 582*da6c28aaSamw 583*da6c28aaSamw int 584*da6c28aaSamw smb_vop_create(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp, 585*da6c28aaSamw int flags, cred_t *cr, caller_context_t *ct, vsecattr_t *vsap) 586*da6c28aaSamw { 587*da6c28aaSamw int error; 588*da6c28aaSamw int option_flags = 0; 589*da6c28aaSamw 590*da6c28aaSamw if (flags & SMB_IGNORE_CASE) 591*da6c28aaSamw option_flags = FIGNORECASE; 592*da6c28aaSamw 593*da6c28aaSamw smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask); 594*da6c28aaSamw 595*da6c28aaSamw error = VOP_CREATE(dvp, name, &attr->sa_vattr, EXCL, 596*da6c28aaSamw attr->sa_vattr.va_mode, vpp, cr, option_flags, ct, vsap); 597*da6c28aaSamw 598*da6c28aaSamw return (error); 599*da6c28aaSamw } 600*da6c28aaSamw 601*da6c28aaSamw int 602*da6c28aaSamw smb_vop_remove(vnode_t *dvp, char *name, int flags, cred_t *cr, 603*da6c28aaSamw caller_context_t *ct) 604*da6c28aaSamw { 605*da6c28aaSamw int error; 606*da6c28aaSamw int option_flags = 0; 607*da6c28aaSamw 608*da6c28aaSamw if (flags & SMB_IGNORE_CASE) 609*da6c28aaSamw option_flags = FIGNORECASE; 610*da6c28aaSamw 611*da6c28aaSamw error = VOP_REMOVE(dvp, name, cr, ct, option_flags); 612*da6c28aaSamw 613*da6c28aaSamw return (error); 614*da6c28aaSamw } 615*da6c28aaSamw 616*da6c28aaSamw /* 617*da6c28aaSamw * smb_vop_rename() 618*da6c28aaSamw * 619*da6c28aaSamw * The rename is for files in the same tree (identical TID) only. 620*da6c28aaSamw */ 621*da6c28aaSamw 622*da6c28aaSamw int 623*da6c28aaSamw smb_vop_rename(vnode_t *from_dvp, char *from_name, vnode_t *to_dvp, 624*da6c28aaSamw char *to_name, int flags, cred_t *cr, caller_context_t *ct) 625*da6c28aaSamw { 626*da6c28aaSamw int error; 627*da6c28aaSamw int option_flags = 0; 628*da6c28aaSamw 629*da6c28aaSamw 630*da6c28aaSamw if (flags & SMB_IGNORE_CASE) 631*da6c28aaSamw option_flags = FIGNORECASE; 632*da6c28aaSamw 633*da6c28aaSamw error = VOP_RENAME(from_dvp, from_name, to_dvp, to_name, cr, 634*da6c28aaSamw ct, option_flags); 635*da6c28aaSamw 636*da6c28aaSamw return (error); 637*da6c28aaSamw } 638*da6c28aaSamw 639*da6c28aaSamw int 640*da6c28aaSamw smb_vop_mkdir(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp, 641*da6c28aaSamw int flags, cred_t *cr, caller_context_t *ct, vsecattr_t *vsap) 642*da6c28aaSamw { 643*da6c28aaSamw int error; 644*da6c28aaSamw int option_flags = 0; 645*da6c28aaSamw 646*da6c28aaSamw 647*da6c28aaSamw 648*da6c28aaSamw if (flags & SMB_IGNORE_CASE) 649*da6c28aaSamw option_flags = FIGNORECASE; 650*da6c28aaSamw 651*da6c28aaSamw smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask); 652*da6c28aaSamw 653*da6c28aaSamw error = VOP_MKDIR(dvp, name, &attr->sa_vattr, vpp, cr, ct, 654*da6c28aaSamw option_flags, vsap); 655*da6c28aaSamw 656*da6c28aaSamw return (error); 657*da6c28aaSamw } 658*da6c28aaSamw 659*da6c28aaSamw /* 660*da6c28aaSamw * smb_vop_rmdir() 661*da6c28aaSamw * 662*da6c28aaSamw * Only simple rmdir supported, consistent with NT semantics 663*da6c28aaSamw * (can only remove an empty directory). 664*da6c28aaSamw * 665*da6c28aaSamw */ 666*da6c28aaSamw 667*da6c28aaSamw int 668*da6c28aaSamw smb_vop_rmdir(vnode_t *dvp, char *name, int flags, cred_t *cr, 669*da6c28aaSamw caller_context_t *ct) 670*da6c28aaSamw { 671*da6c28aaSamw int error; 672*da6c28aaSamw int option_flags = 0; 673*da6c28aaSamw 674*da6c28aaSamw if (flags & SMB_IGNORE_CASE) 675*da6c28aaSamw option_flags = FIGNORECASE; 676*da6c28aaSamw 677*da6c28aaSamw /* 678*da6c28aaSamw * Comments adapted from rfs_rmdir(). 679*da6c28aaSamw * 680*da6c28aaSamw * VOP_RMDIR now takes a new third argument (the current 681*da6c28aaSamw * directory of the process). That's because rmdir 682*da6c28aaSamw * wants to return EINVAL if one tries to remove ".". 683*da6c28aaSamw * Of course, SMB servers do not know what their 684*da6c28aaSamw * clients' current directories are. We fake it by 685*da6c28aaSamw * supplying a vnode known to exist and illegal to 686*da6c28aaSamw * remove. 687*da6c28aaSamw */ 688*da6c28aaSamw 689*da6c28aaSamw error = VOP_RMDIR(dvp, name, rootdir, cr, ct, option_flags); 690*da6c28aaSamw return (error); 691*da6c28aaSamw } 692*da6c28aaSamw 693*da6c28aaSamw int 694*da6c28aaSamw smb_vop_commit(vnode_t *vp, cred_t *cr, caller_context_t *ct) 695*da6c28aaSamw { 696*da6c28aaSamw return (VOP_FSYNC(vp, 1, cr, ct)); 697*da6c28aaSamw } 698*da6c28aaSamw 699*da6c28aaSamw /* 700*da6c28aaSamw * smb_vop_readdir() 701*da6c28aaSamw * 702*da6c28aaSamw * Upon return, the "name" field will contain either the on-disk name or, if 703*da6c28aaSamw * it needs mangling or has a case-insensitive collision, the mangled 704*da6c28aaSamw * "shortname." 705*da6c28aaSamw * 706*da6c28aaSamw * vpp is an optional parameter. If non-NULL, it will contain a pointer to 707*da6c28aaSamw * the vnode for the name that is looked up (the vnode will be returned held). 708*da6c28aaSamw * 709*da6c28aaSamw * od_name is an optional parameter (NULL can be passed if the on-disk name 710*da6c28aaSamw * is not needed by the caller). 711*da6c28aaSamw */ 712*da6c28aaSamw 713*da6c28aaSamw int 714*da6c28aaSamw smb_vop_readdir(vnode_t *dvp, uint32_t *cookiep, char *name, int *namelen, 715*da6c28aaSamw ino64_t *inop, vnode_t **vpp, char *od_name, int flags, cred_t *cr, 716*da6c28aaSamw caller_context_t *ct) 717*da6c28aaSamw { 718*da6c28aaSamw int num_bytes; 719*da6c28aaSamw int error = 0; 720*da6c28aaSamw char *dirbuf = NULL; 721*da6c28aaSamw 722*da6c28aaSamw ASSERT(dvp); 723*da6c28aaSamw ASSERT(cookiep); 724*da6c28aaSamw ASSERT(name); 725*da6c28aaSamw ASSERT(namelen); 726*da6c28aaSamw ASSERT(inop); 727*da6c28aaSamw ASSERT(cr); 728*da6c28aaSamw ASSERT(ct); 729*da6c28aaSamw 730*da6c28aaSamw if (dvp->v_type != VDIR) { 731*da6c28aaSamw *namelen = 0; 732*da6c28aaSamw return (ENOTDIR); 733*da6c28aaSamw } 734*da6c28aaSamw 735*da6c28aaSamw if (vpp) 736*da6c28aaSamw *vpp = NULL; 737*da6c28aaSamw 738*da6c28aaSamw dirbuf = kmem_zalloc(SMB_MINLEN_RDDIR_BUF, KM_SLEEP); 739*da6c28aaSamw num_bytes = SMB_MINLEN_RDDIR_BUF; 740*da6c28aaSamw 741*da6c28aaSamw /* 742*da6c28aaSamw * The goal is to retrieve the first valid entry from *cookiep 743*da6c28aaSamw * forward. smb_vop_readdir_readpage() collects an 744*da6c28aaSamw * SMB_MINLEN_RDDIR_BUF-size "page" of directory entry information. 745*da6c28aaSamw * smb_vop_readdir_entry() attempts to find the first valid entry 746*da6c28aaSamw * in that page. 747*da6c28aaSamw */ 748*da6c28aaSamw 749*da6c28aaSamw while ((error = smb_vop_readdir_readpage(dvp, dirbuf, *cookiep, 750*da6c28aaSamw &num_bytes, cr, ct, flags)) == 0) { 751*da6c28aaSamw 752*da6c28aaSamw if (num_bytes <= 0) 753*da6c28aaSamw break; 754*da6c28aaSamw 755*da6c28aaSamw name[0] = '\0'; 756*da6c28aaSamw 757*da6c28aaSamw error = smb_vop_readdir_entry(dvp, cookiep, name, namelen, 758*da6c28aaSamw inop, vpp, od_name, flags, cr, ct, dirbuf, 759*da6c28aaSamw num_bytes); 760*da6c28aaSamw 761*da6c28aaSamw if (error) 762*da6c28aaSamw break; 763*da6c28aaSamw 764*da6c28aaSamw if (*name) 765*da6c28aaSamw break; 766*da6c28aaSamw 767*da6c28aaSamw bzero(dirbuf, SMB_MINLEN_RDDIR_BUF); 768*da6c28aaSamw num_bytes = SMB_MINLEN_RDDIR_BUF; 769*da6c28aaSamw } 770*da6c28aaSamw 771*da6c28aaSamw 772*da6c28aaSamw if (error) { 773*da6c28aaSamw kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 774*da6c28aaSamw *namelen = 0; 775*da6c28aaSamw return (error); 776*da6c28aaSamw } 777*da6c28aaSamw 778*da6c28aaSamw if (num_bytes == 0) { /* EOF */ 779*da6c28aaSamw kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 780*da6c28aaSamw *cookiep = SMB_EOF; 781*da6c28aaSamw *namelen = 0; 782*da6c28aaSamw return (0); 783*da6c28aaSamw } 784*da6c28aaSamw 785*da6c28aaSamw kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 786*da6c28aaSamw return (0); 787*da6c28aaSamw } 788*da6c28aaSamw 789*da6c28aaSamw /* 790*da6c28aaSamw * smb_vop_readdir_readpage() 791*da6c28aaSamw * 792*da6c28aaSamw * Collects an SMB_MINLEN_RDDIR_BUF "page" of directory entries. (The 793*da6c28aaSamw * directory entries are returned in an fs-independent format by the 794*da6c28aaSamw * underlying file system. That is, the "page" of information returned is 795*da6c28aaSamw * not literally stored on-disk in the format returned.) 796*da6c28aaSamw * 797*da6c28aaSamw * Much of the following is borrowed from getdents64() 798*da6c28aaSamw * 799*da6c28aaSamw * MAXGETDENTS_SIZE is defined in getdents.c 800*da6c28aaSamw */ 801*da6c28aaSamw 802*da6c28aaSamw #define MAXGETDENTS_SIZE (64 * 1024) 803*da6c28aaSamw 804*da6c28aaSamw static int 805*da6c28aaSamw smb_vop_readdir_readpage(vnode_t *vp, void *buf, uint32_t offset, int *count, 806*da6c28aaSamw cred_t *cr, caller_context_t *ct, int flags) 807*da6c28aaSamw { 808*da6c28aaSamw int error = 0; 809*da6c28aaSamw int rdirent_flags = 0; 810*da6c28aaSamw int sink; 811*da6c28aaSamw struct uio auio; 812*da6c28aaSamw struct iovec aiov; 813*da6c28aaSamw 814*da6c28aaSamw if (vp->v_type != VDIR) 815*da6c28aaSamw return (ENOTDIR); 816*da6c28aaSamw 817*da6c28aaSamw /* entflags not working for streams so don't try to use them */ 818*da6c28aaSamw if (!(flags & SMB_STREAM_RDDIR) && 819*da6c28aaSamw (vfs_has_feature(vp->v_vfsp, VFSFT_DIRENTFLAGS))) { 820*da6c28aaSamw /* 821*da6c28aaSamw * Setting V_RDDIR_ENTFLAGS will cause the buffer to 822*da6c28aaSamw * be filled with edirent_t structures (instead of 823*da6c28aaSamw * dirent64_t structures). 824*da6c28aaSamw */ 825*da6c28aaSamw rdirent_flags = V_RDDIR_ENTFLAGS; 826*da6c28aaSamw 827*da6c28aaSamw if (*count < sizeof (edirent_t)) 828*da6c28aaSamw return (EINVAL); 829*da6c28aaSamw } else { 830*da6c28aaSamw if (*count < sizeof (dirent64_t)) 831*da6c28aaSamw return (EINVAL); 832*da6c28aaSamw } 833*da6c28aaSamw 834*da6c28aaSamw if (*count > MAXGETDENTS_SIZE) 835*da6c28aaSamw *count = MAXGETDENTS_SIZE; 836*da6c28aaSamw 837*da6c28aaSamw aiov.iov_base = buf; 838*da6c28aaSamw aiov.iov_len = *count; 839*da6c28aaSamw auio.uio_iov = &aiov; 840*da6c28aaSamw auio.uio_iovcnt = 1; 841*da6c28aaSamw auio.uio_loffset = (uint64_t)offset; 842*da6c28aaSamw auio.uio_segflg = UIO_SYSSPACE; 843*da6c28aaSamw auio.uio_resid = *count; 844*da6c28aaSamw auio.uio_fmode = 0; 845*da6c28aaSamw 846*da6c28aaSamw (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL); 847*da6c28aaSamw error = VOP_READDIR(vp, &auio, cr, &sink, ct, rdirent_flags); 848*da6c28aaSamw VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 849*da6c28aaSamw 850*da6c28aaSamw if (error) { 851*da6c28aaSamw if (error == ENOENT) { 852*da6c28aaSamw /* Fake EOF if offset is bad due to dropping of lock */ 853*da6c28aaSamw *count = 0; 854*da6c28aaSamw return (0); 855*da6c28aaSamw } else { 856*da6c28aaSamw return (error); 857*da6c28aaSamw } 858*da6c28aaSamw } 859*da6c28aaSamw 860*da6c28aaSamw /* 861*da6c28aaSamw * Windows cannot handle an offset > SMB_EOF. 862*da6c28aaSamw * Pretend we are at EOF. 863*da6c28aaSamw */ 864*da6c28aaSamw 865*da6c28aaSamw if (auio.uio_loffset > SMB_EOF) { 866*da6c28aaSamw *count = 0; 867*da6c28aaSamw return (0); 868*da6c28aaSamw } 869*da6c28aaSamw 870*da6c28aaSamw *count = *count - auio.uio_resid; 871*da6c28aaSamw return (0); 872*da6c28aaSamw } 873*da6c28aaSamw 874*da6c28aaSamw /* 875*da6c28aaSamw * smb_vop_readdir_entry() 876*da6c28aaSamw * 877*da6c28aaSamw * This function retrieves the first valid entry from the 878*da6c28aaSamw * SMB_MINLEN_RDDIR_BUF-sized buffer returned by smb_vop_readdir_readpage() 879*da6c28aaSamw * to smb_vop_readdir(). 880*da6c28aaSamw * 881*da6c28aaSamw * Both dirent64_t and edirent_t structures need to be handled. The former is 882*da6c28aaSamw * needed for file systems that do not support VFSFT_DIRENTFLAGS. The latter 883*da6c28aaSamw * is required for proper handling of case collisions on file systems that 884*da6c28aaSamw * support case-insensitivity. edirent_t structures are also used for 885*da6c28aaSamw * case-sensitive file systems if VFSFT_DIRENTFLAGS is supported. 886*da6c28aaSamw */ 887*da6c28aaSamw 888*da6c28aaSamw static int 889*da6c28aaSamw smb_vop_readdir_entry(vnode_t *dvp, uint32_t *cookiep, char *name, int *namelen, 890*da6c28aaSamw ino64_t *inop, vnode_t **vpp, char *od_name, int flags, cred_t *cr, 891*da6c28aaSamw caller_context_t *ct, char *dirbuf, int num_bytes) 892*da6c28aaSamw { 893*da6c28aaSamw uint32_t next_cookie; 894*da6c28aaSamw int ebufsize; 895*da6c28aaSamw int error = 0; 896*da6c28aaSamw int len; 897*da6c28aaSamw int rc; 898*da6c28aaSamw char shortname[MANGLE_NAMELEN]; 899*da6c28aaSamw char name83[MANGLE_NAMELEN]; 900*da6c28aaSamw char *ebuf = NULL; 901*da6c28aaSamw edirent_t *edp; 902*da6c28aaSamw dirent64_t *dp = NULL; 903*da6c28aaSamw vnode_t *vp = NULL; 904*da6c28aaSamw 905*da6c28aaSamw ASSERT(dirbuf); 906*da6c28aaSamw 907*da6c28aaSamw /* 908*da6c28aaSamw * Use edirent_t structure for both 909*da6c28aaSamw * entflags not working for streams so don't try to use them 910*da6c28aaSamw */ 911*da6c28aaSamw if (!(flags & SMB_STREAM_RDDIR) && 912*da6c28aaSamw (vfs_has_feature(dvp->v_vfsp, VFSFT_DIRENTFLAGS))) { 913*da6c28aaSamw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 914*da6c28aaSamw edp = (edirent_t *)dirbuf; 915*da6c28aaSamw } else { 916*da6c28aaSamw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 917*da6c28aaSamw dp = (dirent64_t *)dirbuf; 918*da6c28aaSamw ebufsize = EDIRENT_RECLEN(MAXNAMELEN); 919*da6c28aaSamw ebuf = kmem_zalloc(ebufsize, KM_SLEEP); 920*da6c28aaSamw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 921*da6c28aaSamw edp = (edirent_t *)ebuf; 922*da6c28aaSamw } 923*da6c28aaSamw 924*da6c28aaSamw while (edp) { 925*da6c28aaSamw if (dp) 926*da6c28aaSamw DP_TO_EDP(dp, edp); 927*da6c28aaSamw 928*da6c28aaSamw next_cookie = (uint32_t)edp->ed_off; 929*da6c28aaSamw if (edp->ed_ino == 0) { 930*da6c28aaSamw *cookiep = next_cookie; 931*da6c28aaSamw 932*da6c28aaSamw if (dp) { 933*da6c28aaSamw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 934*da6c28aaSamw DP_ADVANCE(dp, dirbuf, num_bytes); 935*da6c28aaSamw if (dp == NULL) 936*da6c28aaSamw edp = NULL; 937*da6c28aaSamw } else { 938*da6c28aaSamw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 939*da6c28aaSamw EDP_ADVANCE(edp, dirbuf, num_bytes); 940*da6c28aaSamw } 941*da6c28aaSamw continue; 942*da6c28aaSamw } 943*da6c28aaSamw 944*da6c28aaSamw len = strlen(edp->ed_name); 945*da6c28aaSamw 946*da6c28aaSamw if (*namelen < len) { 947*da6c28aaSamw *namelen = 0; 948*da6c28aaSamw 949*da6c28aaSamw if (ebuf) 950*da6c28aaSamw kmem_free(ebuf, ebufsize); 951*da6c28aaSamw 952*da6c28aaSamw return (EOVERFLOW); 953*da6c28aaSamw } 954*da6c28aaSamw 955*da6c28aaSamw /* 956*da6c28aaSamw * Do not pass SMB_IGNORE_CASE to smb_vop_lookup 957*da6c28aaSamw */ 958*da6c28aaSamw 959*da6c28aaSamw error = smb_vop_lookup(dvp, edp->ed_name, vpp ? vpp : &vp, 960*da6c28aaSamw od_name, 0, NULL, cr, ct); 961*da6c28aaSamw 962*da6c28aaSamw if (error) { 963*da6c28aaSamw if (error == ENOENT) { 964*da6c28aaSamw *cookiep = (uint32_t)next_cookie; 965*da6c28aaSamw 966*da6c28aaSamw if (dp) { 967*da6c28aaSamw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 968*da6c28aaSamw DP_ADVANCE(dp, dirbuf, num_bytes); 969*da6c28aaSamw if (dp == NULL) 970*da6c28aaSamw edp = NULL; 971*da6c28aaSamw } else { 972*da6c28aaSamw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 973*da6c28aaSamw EDP_ADVANCE(edp, dirbuf, num_bytes); 974*da6c28aaSamw } 975*da6c28aaSamw continue; 976*da6c28aaSamw } 977*da6c28aaSamw 978*da6c28aaSamw 979*da6c28aaSamw *namelen = 0; 980*da6c28aaSamw 981*da6c28aaSamw if (ebuf) 982*da6c28aaSamw kmem_free(ebuf, ebufsize); 983*da6c28aaSamw 984*da6c28aaSamw return (error); 985*da6c28aaSamw } 986*da6c28aaSamw 987*da6c28aaSamw if ((flags & SMB_IGNORE_CASE) && ED_CASE_CONFLICTS(edp)) { 988*da6c28aaSamw rc = smb_mangle_name(edp->ed_ino, edp->ed_name, 989*da6c28aaSamw shortname, name83, 1); 990*da6c28aaSamw 991*da6c28aaSamw if (rc == 1) { /* success */ 992*da6c28aaSamw (void) strlcpy(name, shortname, *namelen + 1); 993*da6c28aaSamw *namelen = strlen(shortname); 994*da6c28aaSamw } else { 995*da6c28aaSamw (void) strlcpy(name, edp->ed_name, 996*da6c28aaSamw *namelen + 1); 997*da6c28aaSamw name[*namelen] = '\0'; 998*da6c28aaSamw } 999*da6c28aaSamw 1000*da6c28aaSamw } else { 1001*da6c28aaSamw (void) strlcpy(name, edp->ed_name, *namelen + 1); 1002*da6c28aaSamw *namelen = len; 1003*da6c28aaSamw } 1004*da6c28aaSamw 1005*da6c28aaSamw if (vpp == NULL) 1006*da6c28aaSamw VN_RELE(vp); 1007*da6c28aaSamw 1008*da6c28aaSamw if (inop) 1009*da6c28aaSamw *inop = edp->ed_ino; 1010*da6c28aaSamw 1011*da6c28aaSamw *cookiep = (uint32_t)next_cookie; 1012*da6c28aaSamw break; 1013*da6c28aaSamw } 1014*da6c28aaSamw 1015*da6c28aaSamw if (ebuf) 1016*da6c28aaSamw kmem_free(ebuf, ebufsize); 1017*da6c28aaSamw 1018*da6c28aaSamw return (error); 1019*da6c28aaSamw } 1020*da6c28aaSamw 1021*da6c28aaSamw /* 1022*da6c28aaSamw * smb_sa_to_va_mask 1023*da6c28aaSamw * 1024*da6c28aaSamw * Set va_mask by running through the SMB_AT_* #define's and 1025*da6c28aaSamw * setting those bits that correspond to the SMB_AT_* bits 1026*da6c28aaSamw * set in sa_mask. 1027*da6c28aaSamw */ 1028*da6c28aaSamw 1029*da6c28aaSamw void 1030*da6c28aaSamw smb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp) 1031*da6c28aaSamw { 1032*da6c28aaSamw int i; 1033*da6c28aaSamw uint_t smask; 1034*da6c28aaSamw 1035*da6c28aaSamw smask = (sa_mask); 1036*da6c28aaSamw for (i = SMB_AT_TYPE; (i < SMB_AT_MAX) && (smask != 0); ++i) { 1037*da6c28aaSamw if (smask & 1) 1038*da6c28aaSamw *(va_maskp) |= smb_attrmap[i]; 1039*da6c28aaSamw 1040*da6c28aaSamw smask >>= 1; 1041*da6c28aaSamw } 1042*da6c28aaSamw } 1043*da6c28aaSamw 1044*da6c28aaSamw /* 1045*da6c28aaSamw * smb_vop_getdents() 1046*da6c28aaSamw * 1047*da6c28aaSamw * Upon success, the smb_node corresponding to each entry returned will 1048*da6c28aaSamw * have a reference taken on it. These will be released in 1049*da6c28aaSamw * smb_trans2_find_get_dents(). 1050*da6c28aaSamw * 1051*da6c28aaSamw * If an error is returned from this routine, a list of already processed 1052*da6c28aaSamw * entries will be returned. The smb_nodes corresponding to these entries 1053*da6c28aaSamw * will be referenced, and will be released in smb_trans2_find_get_dents(). 1054*da6c28aaSamw * 1055*da6c28aaSamw * The returned dp->d_name field will contain either the on-disk name or, if 1056*da6c28aaSamw * it needs mangling or has a case-insensitive collision, the mangled 1057*da6c28aaSamw * "shortname." In this case, the on-disk name can be retrieved from the 1058*da6c28aaSamw * smb_node's od_name (the smb_node is passed to smb_gather_dents_info()). 1059*da6c28aaSamw */ 1060*da6c28aaSamw 1061*da6c28aaSamw int /*ARGSUSED*/ 1062*da6c28aaSamw smb_vop_getdents( 1063*da6c28aaSamw smb_node_t *dir_snode, 1064*da6c28aaSamw uint32_t *cookiep, 1065*da6c28aaSamw uint64_t *verifierp, 1066*da6c28aaSamw int32_t *dircountp, 1067*da6c28aaSamw char *arg, 1068*da6c28aaSamw char *pattern, 1069*da6c28aaSamw uint32_t flags, 1070*da6c28aaSamw smb_request_t *sr, 1071*da6c28aaSamw cred_t *cr, 1072*da6c28aaSamw caller_context_t *ct) 1073*da6c28aaSamw { 1074*da6c28aaSamw int error = 0; 1075*da6c28aaSamw int maxentries; 1076*da6c28aaSamw int num_bytes; 1077*da6c28aaSamw int resid; 1078*da6c28aaSamw char *dirbuf = NULL; 1079*da6c28aaSamw vnode_t *dvp; 1080*da6c28aaSamw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1081*da6c28aaSamw smb_dent_info_hdr_t *ihdr = (smb_dent_info_hdr_t *)arg; 1082*da6c28aaSamw 1083*da6c28aaSamw dvp = dir_snode->vp; 1084*da6c28aaSamw 1085*da6c28aaSamw resid = ihdr->uio.uio_resid; 1086*da6c28aaSamw maxentries = resid / SMB_MAX_DENT_INFO_SIZE; 1087*da6c28aaSamw 1088*da6c28aaSamw bzero(ihdr->iov->iov_base, resid); 1089*da6c28aaSamw 1090*da6c28aaSamw dirbuf = kmem_alloc(SMB_MINLEN_RDDIR_BUF, KM_SLEEP); 1091*da6c28aaSamw 1092*da6c28aaSamw while (maxentries) { 1093*da6c28aaSamw 1094*da6c28aaSamw bzero(dirbuf, SMB_MINLEN_RDDIR_BUF); 1095*da6c28aaSamw 1096*da6c28aaSamw num_bytes = SMB_MINLEN_RDDIR_BUF; 1097*da6c28aaSamw error = smb_vop_readdir_readpage(dvp, dirbuf, *cookiep, 1098*da6c28aaSamw &num_bytes, cr, ct, flags); 1099*da6c28aaSamw 1100*da6c28aaSamw if (error || (num_bytes <= 0)) 1101*da6c28aaSamw break; 1102*da6c28aaSamw 1103*da6c28aaSamw error = smb_vop_getdents_entries(dir_snode, cookiep, dircountp, 1104*da6c28aaSamw arg, flags, sr, cr, ct, dirbuf, &maxentries, num_bytes, 1105*da6c28aaSamw pattern); 1106*da6c28aaSamw 1107*da6c28aaSamw if (error) 1108*da6c28aaSamw goto out; 1109*da6c28aaSamw } 1110*da6c28aaSamw 1111*da6c28aaSamw if (num_bytes < 0) { 1112*da6c28aaSamw error = -1; 1113*da6c28aaSamw } else if (num_bytes == 0) { 1114*da6c28aaSamw *cookiep = SMB_EOF; 1115*da6c28aaSamw error = 0; 1116*da6c28aaSamw } else { 1117*da6c28aaSamw error = 0; 1118*da6c28aaSamw } 1119*da6c28aaSamw 1120*da6c28aaSamw out: 1121*da6c28aaSamw if (dirbuf) 1122*da6c28aaSamw kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 1123*da6c28aaSamw 1124*da6c28aaSamw return (error); 1125*da6c28aaSamw } 1126*da6c28aaSamw 1127*da6c28aaSamw /* 1128*da6c28aaSamw * smb_vop_getdents_entries() 1129*da6c28aaSamw * 1130*da6c28aaSamw * This function retrieves names from the SMB_MINLEN_RDDIR_BUF-sized buffer 1131*da6c28aaSamw * returned by smb_vop_readdir_readpage() to smb_vop_getdents(). 1132*da6c28aaSamw * 1133*da6c28aaSamw * Both dirent64_t and edirent_t structures need to be handled. The former is 1134*da6c28aaSamw * needed for file systems that do not support VFSFT_DIRENTFLAGS. The latter 1135*da6c28aaSamw * is required for properly handling case collisions on file systems that 1136*da6c28aaSamw * support case-insensitivity. edirent_t is also used on case-sensitive 1137*da6c28aaSamw * file systems where VFSFT_DIRENTFLAGS is available. 1138*da6c28aaSamw */ 1139*da6c28aaSamw 1140*da6c28aaSamw static int 1141*da6c28aaSamw smb_vop_getdents_entries( 1142*da6c28aaSamw smb_node_t *dir_snode, 1143*da6c28aaSamw uint32_t *cookiep, 1144*da6c28aaSamw int32_t *dircountp, 1145*da6c28aaSamw char *arg, 1146*da6c28aaSamw uint32_t flags, 1147*da6c28aaSamw struct smb_request *sr, 1148*da6c28aaSamw cred_t *cr, 1149*da6c28aaSamw caller_context_t *ct, 1150*da6c28aaSamw char *dirbuf, 1151*da6c28aaSamw int *maxentries, 1152*da6c28aaSamw int num_bytes, 1153*da6c28aaSamw char *pattern) 1154*da6c28aaSamw { 1155*da6c28aaSamw uint32_t next_cookie; 1156*da6c28aaSamw int ebufsize; 1157*da6c28aaSamw char *tmp_name; 1158*da6c28aaSamw int error; 1159*da6c28aaSamw int rc; 1160*da6c28aaSamw char shortname[MANGLE_NAMELEN]; 1161*da6c28aaSamw char name83[MANGLE_NAMELEN]; 1162*da6c28aaSamw char *ebuf = NULL; 1163*da6c28aaSamw dirent64_t *dp = NULL; 1164*da6c28aaSamw edirent_t *edp; 1165*da6c28aaSamw smb_node_t *ret_snode; 1166*da6c28aaSamw smb_attr_t ret_attr; 1167*da6c28aaSamw vnode_t *dvp; 1168*da6c28aaSamw vnode_t *fvp; 1169*da6c28aaSamw 1170*da6c28aaSamw ASSERT(dirbuf); 1171*da6c28aaSamw 1172*da6c28aaSamw dvp = dir_snode->vp; 1173*da6c28aaSamw 1174*da6c28aaSamw if (vfs_has_feature(dvp->v_vfsp, VFSFT_DIRENTFLAGS)) { 1175*da6c28aaSamw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1176*da6c28aaSamw edp = (edirent_t *)dirbuf; 1177*da6c28aaSamw } else { 1178*da6c28aaSamw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1179*da6c28aaSamw dp = (dirent64_t *)dirbuf; 1180*da6c28aaSamw ebufsize = EDIRENT_RECLEN(MAXNAMELEN); 1181*da6c28aaSamw ebuf = kmem_zalloc(ebufsize, KM_SLEEP); 1182*da6c28aaSamw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1183*da6c28aaSamw edp = (edirent_t *)ebuf; 1184*da6c28aaSamw } 1185*da6c28aaSamw 1186*da6c28aaSamw while (edp) { 1187*da6c28aaSamw if (dp) 1188*da6c28aaSamw DP_TO_EDP(dp, edp); 1189*da6c28aaSamw 1190*da6c28aaSamw if (*maxentries == 0) 1191*da6c28aaSamw break; 1192*da6c28aaSamw 1193*da6c28aaSamw next_cookie = (uint32_t)edp->ed_off; 1194*da6c28aaSamw 1195*da6c28aaSamw if (edp->ed_ino == 0) { 1196*da6c28aaSamw *cookiep = next_cookie; 1197*da6c28aaSamw if (dp) { 1198*da6c28aaSamw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1199*da6c28aaSamw DP_ADVANCE(dp, dirbuf, num_bytes); 1200*da6c28aaSamw if (dp == NULL) 1201*da6c28aaSamw edp = NULL; 1202*da6c28aaSamw } else { 1203*da6c28aaSamw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1204*da6c28aaSamw EDP_ADVANCE(edp, dirbuf, num_bytes); 1205*da6c28aaSamw } 1206*da6c28aaSamw continue; 1207*da6c28aaSamw } 1208*da6c28aaSamw 1209*da6c28aaSamw error = smb_vop_lookup(dvp, edp->ed_name, &fvp, 1210*da6c28aaSamw NULL, 0, NULL, cr, ct); 1211*da6c28aaSamw 1212*da6c28aaSamw if (error) { 1213*da6c28aaSamw if (error == ENOENT) { 1214*da6c28aaSamw *cookiep = next_cookie; 1215*da6c28aaSamw if (dp) { 1216*da6c28aaSamw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1217*da6c28aaSamw DP_ADVANCE(dp, dirbuf, 1218*da6c28aaSamw num_bytes); 1219*da6c28aaSamw if (dp == NULL) 1220*da6c28aaSamw edp = NULL; 1221*da6c28aaSamw } else { 1222*da6c28aaSamw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1223*da6c28aaSamw EDP_ADVANCE(edp, dirbuf, 1224*da6c28aaSamw num_bytes); 1225*da6c28aaSamw } 1226*da6c28aaSamw continue; 1227*da6c28aaSamw } 1228*da6c28aaSamw if (ebuf) 1229*da6c28aaSamw kmem_free(ebuf, ebufsize); 1230*da6c28aaSamw 1231*da6c28aaSamw return (error); 1232*da6c28aaSamw } 1233*da6c28aaSamw 1234*da6c28aaSamw ret_snode = smb_node_lookup(sr, NULL, cr, fvp, 1235*da6c28aaSamw edp->ed_name, dir_snode, NULL, &ret_attr); 1236*da6c28aaSamw 1237*da6c28aaSamw if (ret_snode == NULL) { 1238*da6c28aaSamw VN_RELE(fvp); 1239*da6c28aaSamw 1240*da6c28aaSamw if (ebuf) 1241*da6c28aaSamw kmem_free(ebuf, ebufsize); 1242*da6c28aaSamw 1243*da6c28aaSamw return (ENOMEM); 1244*da6c28aaSamw } 1245*da6c28aaSamw 1246*da6c28aaSamw if (smb_match_name(edp->ed_ino, edp->ed_name, shortname, 1247*da6c28aaSamw name83, pattern, (flags & SMB_IGNORE_CASE))) { 1248*da6c28aaSamw 1249*da6c28aaSamw tmp_name = edp->ed_name; 1250*da6c28aaSamw 1251*da6c28aaSamw if ((flags & SMB_IGNORE_CASE) && 1252*da6c28aaSamw ED_CASE_CONFLICTS(edp)) { 1253*da6c28aaSamw rc = smb_mangle_name(edp->ed_ino, edp->ed_name, 1254*da6c28aaSamw shortname, name83, 1); 1255*da6c28aaSamw if (rc == 1) 1256*da6c28aaSamw tmp_name = shortname; 1257*da6c28aaSamw } else { 1258*da6c28aaSamw rc = smb_mangle_name(edp->ed_ino, edp->ed_name, 1259*da6c28aaSamw shortname, name83, 0); 1260*da6c28aaSamw } 1261*da6c28aaSamw 1262*da6c28aaSamw if (rc != 1) { 1263*da6c28aaSamw (void) strlcpy(shortname, edp->ed_name, 1264*da6c28aaSamw MANGLE_NAMELEN); 1265*da6c28aaSamw (void) strlcpy(name83, edp->ed_name, 1266*da6c28aaSamw MANGLE_NAMELEN); 1267*da6c28aaSamw shortname[MANGLE_NAMELEN - 1] = '\0'; 1268*da6c28aaSamw name83[MANGLE_NAMELEN - 1] = '\0'; 1269*da6c28aaSamw } 1270*da6c28aaSamw 1271*da6c28aaSamw error = smb_gather_dents_info(arg, edp->ed_ino, 1272*da6c28aaSamw strlen(tmp_name), tmp_name, next_cookie, dircountp, 1273*da6c28aaSamw &ret_attr, ret_snode, shortname, name83); 1274*da6c28aaSamw 1275*da6c28aaSamw if (error > 0) { 1276*da6c28aaSamw if (ebuf) 1277*da6c28aaSamw kmem_free(ebuf, ebufsize); 1278*da6c28aaSamw return (error); 1279*da6c28aaSamw } 1280*da6c28aaSamw 1281*da6c28aaSamw /* 1282*da6c28aaSamw * Treat errors from smb_gather_dents_info() that are 1283*da6c28aaSamw * < 0 the same as EOF. 1284*da6c28aaSamw */ 1285*da6c28aaSamw if (error < 0) { 1286*da6c28aaSamw if (ebuf) 1287*da6c28aaSamw kmem_free(ebuf, ebufsize); 1288*da6c28aaSamw *maxentries = 0; 1289*da6c28aaSamw return (0); 1290*da6c28aaSamw } 1291*da6c28aaSamw (*maxentries)--; 1292*da6c28aaSamw } else { 1293*da6c28aaSamw smb_node_release(ret_snode); 1294*da6c28aaSamw } 1295*da6c28aaSamw 1296*da6c28aaSamw *cookiep = next_cookie; 1297*da6c28aaSamw 1298*da6c28aaSamw if (dp) { 1299*da6c28aaSamw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1300*da6c28aaSamw DP_ADVANCE(dp, dirbuf, num_bytes); 1301*da6c28aaSamw if (dp == NULL) 1302*da6c28aaSamw edp = NULL; 1303*da6c28aaSamw } else { 1304*da6c28aaSamw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 1305*da6c28aaSamw EDP_ADVANCE(edp, dirbuf, num_bytes); 1306*da6c28aaSamw } 1307*da6c28aaSamw } 1308*da6c28aaSamw 1309*da6c28aaSamw if (ebuf) 1310*da6c28aaSamw kmem_free(ebuf, ebufsize); 1311*da6c28aaSamw 1312*da6c28aaSamw return (0); 1313*da6c28aaSamw } 1314*da6c28aaSamw 1315*da6c28aaSamw /* 1316*da6c28aaSamw * smb_vop_stream_lookup() 1317*da6c28aaSamw * 1318*da6c28aaSamw * The name returned in od_name is the on-disk name of the stream with the 1319*da6c28aaSamw * SMB_STREAM_PREFIX stripped off. od_name should be allocated to MAXNAMELEN 1320*da6c28aaSamw * by the caller. 1321*da6c28aaSamw */ 1322*da6c28aaSamw 1323*da6c28aaSamw int 1324*da6c28aaSamw smb_vop_stream_lookup(vnode_t *fvp, char *stream_name, vnode_t **vpp, 1325*da6c28aaSamw char *od_name, vnode_t **xattrdirvpp, int flags, vnode_t *rootvp, 1326*da6c28aaSamw cred_t *cr, caller_context_t *ct) 1327*da6c28aaSamw { 1328*da6c28aaSamw char *solaris_stream_name; 1329*da6c28aaSamw char *name; 1330*da6c28aaSamw int error; 1331*da6c28aaSamw 1332*da6c28aaSamw if ((error = smb_vop_lookup_xattrdir(fvp, xattrdirvpp, 1333*da6c28aaSamw LOOKUP_XATTR | CREATE_XATTR_DIR, cr, ct)) != 0) 1334*da6c28aaSamw return (error); 1335*da6c28aaSamw 1336*da6c28aaSamw /* 1337*da6c28aaSamw * Prepend SMB_STREAM_PREFIX to stream name 1338*da6c28aaSamw */ 1339*da6c28aaSamw 1340*da6c28aaSamw solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1341*da6c28aaSamw (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX, 1342*da6c28aaSamw stream_name); 1343*da6c28aaSamw 1344*da6c28aaSamw /* 1345*da6c28aaSamw * "name" will hold the on-disk name returned from smb_vop_lookup 1346*da6c28aaSamw * for the stream, including the SMB_STREAM_PREFIX. 1347*da6c28aaSamw */ 1348*da6c28aaSamw 1349*da6c28aaSamw name = kmem_zalloc(MAXNAMELEN, KM_SLEEP); 1350*da6c28aaSamw 1351*da6c28aaSamw if ((error = smb_vop_lookup(*xattrdirvpp, solaris_stream_name, vpp, 1352*da6c28aaSamw name, flags, rootvp, cr, ct)) != 0) { 1353*da6c28aaSamw VN_RELE(*xattrdirvpp); 1354*da6c28aaSamw } else { 1355*da6c28aaSamw (void) strlcpy(od_name, &(name[SMB_STREAM_PREFIX_LEN]), 1356*da6c28aaSamw MAXNAMELEN); 1357*da6c28aaSamw } 1358*da6c28aaSamw 1359*da6c28aaSamw kmem_free(solaris_stream_name, MAXNAMELEN); 1360*da6c28aaSamw kmem_free(name, MAXNAMELEN); 1361*da6c28aaSamw 1362*da6c28aaSamw return (error); 1363*da6c28aaSamw } 1364*da6c28aaSamw 1365*da6c28aaSamw int 1366*da6c28aaSamw smb_vop_stream_create(vnode_t *fvp, char *stream_name, smb_attr_t *attr, 1367*da6c28aaSamw vnode_t **vpp, vnode_t **xattrdirvpp, int flags, cred_t *cr, 1368*da6c28aaSamw caller_context_t *ct) 1369*da6c28aaSamw { 1370*da6c28aaSamw char *solaris_stream_name; 1371*da6c28aaSamw int error; 1372*da6c28aaSamw 1373*da6c28aaSamw if ((error = smb_vop_lookup_xattrdir(fvp, xattrdirvpp, 1374*da6c28aaSamw LOOKUP_XATTR | CREATE_XATTR_DIR, cr, ct)) != 0) 1375*da6c28aaSamw return (error); 1376*da6c28aaSamw 1377*da6c28aaSamw /* 1378*da6c28aaSamw * Prepend SMB_STREAM_PREFIX to stream name 1379*da6c28aaSamw */ 1380*da6c28aaSamw 1381*da6c28aaSamw solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1382*da6c28aaSamw (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX, 1383*da6c28aaSamw stream_name); 1384*da6c28aaSamw 1385*da6c28aaSamw if ((error = smb_vop_create(*xattrdirvpp, solaris_stream_name, attr, 1386*da6c28aaSamw vpp, flags, cr, ct, NULL)) != 0) 1387*da6c28aaSamw VN_RELE(*xattrdirvpp); 1388*da6c28aaSamw 1389*da6c28aaSamw kmem_free(solaris_stream_name, MAXNAMELEN); 1390*da6c28aaSamw 1391*da6c28aaSamw return (error); 1392*da6c28aaSamw } 1393*da6c28aaSamw 1394*da6c28aaSamw int 1395*da6c28aaSamw smb_vop_stream_remove(vnode_t *vp, char *stream_name, int flags, cred_t *cr, 1396*da6c28aaSamw caller_context_t *ct) 1397*da6c28aaSamw { 1398*da6c28aaSamw char *solaris_stream_name; 1399*da6c28aaSamw vnode_t *xattrdirvp; 1400*da6c28aaSamw int error; 1401*da6c28aaSamw 1402*da6c28aaSamw if ((error = smb_vop_lookup_xattrdir(vp, &xattrdirvp, LOOKUP_XATTR, cr, 1403*da6c28aaSamw ct)) != 0) 1404*da6c28aaSamw return (error); 1405*da6c28aaSamw 1406*da6c28aaSamw /* 1407*da6c28aaSamw * Prepend SMB_STREAM_PREFIX to stream name 1408*da6c28aaSamw */ 1409*da6c28aaSamw 1410*da6c28aaSamw solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 1411*da6c28aaSamw (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX, 1412*da6c28aaSamw stream_name); 1413*da6c28aaSamw 1414*da6c28aaSamw /* XXX might have to use kcred */ 1415*da6c28aaSamw error = smb_vop_remove(xattrdirvp, solaris_stream_name, flags, cr, ct); 1416*da6c28aaSamw 1417*da6c28aaSamw kmem_free(solaris_stream_name, MAXNAMELEN); 1418*da6c28aaSamw 1419*da6c28aaSamw return (error); 1420*da6c28aaSamw } 1421*da6c28aaSamw 1422*da6c28aaSamw /* 1423*da6c28aaSamw * smb_vop_stream_readdir() 1424*da6c28aaSamw * 1425*da6c28aaSamw * Note: stream_info.size is not filled in in this routine. 1426*da6c28aaSamw * It needs to be filled in by the caller due to the parameters for getattr. 1427*da6c28aaSamw * 1428*da6c28aaSamw * stream_info.name is set to the on-disk stream name with the SMB_STREAM_PREFIX 1429*da6c28aaSamw * removed. 1430*da6c28aaSamw */ 1431*da6c28aaSamw 1432*da6c28aaSamw int 1433*da6c28aaSamw smb_vop_stream_readdir(vnode_t *fvp, uint32_t *cookiep, 1434*da6c28aaSamw struct fs_stream_info *stream_info, vnode_t **vpp, vnode_t **xattrdirvpp, 1435*da6c28aaSamw int flags, cred_t *cr, caller_context_t *ct) 1436*da6c28aaSamw { 1437*da6c28aaSamw int nsize = MAXNAMELEN-1; 1438*da6c28aaSamw int error = 0; 1439*da6c28aaSamw ino64_t ino; 1440*da6c28aaSamw char *tmp_name; 1441*da6c28aaSamw vnode_t *xattrdirvp; 1442*da6c28aaSamw vnode_t *vp; 1443*da6c28aaSamw 1444*da6c28aaSamw if ((error = smb_vop_lookup_xattrdir(fvp, &xattrdirvp, LOOKUP_XATTR, 1445*da6c28aaSamw cr, ct)) != 0) 1446*da6c28aaSamw return (error); 1447*da6c28aaSamw 1448*da6c28aaSamw bzero(stream_info->name, sizeof (stream_info->name)); 1449*da6c28aaSamw stream_info->size = 0; 1450*da6c28aaSamw 1451*da6c28aaSamw tmp_name = kmem_zalloc(MAXNAMELEN, KM_SLEEP); 1452*da6c28aaSamw 1453*da6c28aaSamw for (;;) { 1454*da6c28aaSamw error = smb_vop_readdir(xattrdirvp, cookiep, tmp_name, &nsize, 1455*da6c28aaSamw &ino, &vp, NULL, flags | SMB_STREAM_RDDIR, cr, ct); 1456*da6c28aaSamw 1457*da6c28aaSamw if (error || (*cookiep == SMB_EOF)) 1458*da6c28aaSamw break; 1459*da6c28aaSamw 1460*da6c28aaSamw if (strncmp(tmp_name, SMB_STREAM_PREFIX, 1461*da6c28aaSamw SMB_STREAM_PREFIX_LEN)) { 1462*da6c28aaSamw VN_RELE(vp); 1463*da6c28aaSamw continue; 1464*da6c28aaSamw } 1465*da6c28aaSamw 1466*da6c28aaSamw tmp_name[nsize] = '\0'; 1467*da6c28aaSamw (void) strlcpy(stream_info->name, 1468*da6c28aaSamw &(tmp_name[SMB_STREAM_PREFIX_LEN]), 1469*da6c28aaSamw sizeof (stream_info->name)); 1470*da6c28aaSamw 1471*da6c28aaSamw nsize -= SMB_STREAM_PREFIX_LEN; 1472*da6c28aaSamw break; 1473*da6c28aaSamw } 1474*da6c28aaSamw 1475*da6c28aaSamw if ((error == 0) && nsize) { 1476*da6c28aaSamw if (vpp) 1477*da6c28aaSamw *vpp = vp; 1478*da6c28aaSamw else 1479*da6c28aaSamw VN_RELE(vp); 1480*da6c28aaSamw 1481*da6c28aaSamw if (xattrdirvpp) 1482*da6c28aaSamw *xattrdirvpp = xattrdirvp; 1483*da6c28aaSamw else 1484*da6c28aaSamw VN_RELE(xattrdirvp); 1485*da6c28aaSamw 1486*da6c28aaSamw } 1487*da6c28aaSamw 1488*da6c28aaSamw kmem_free(tmp_name, MAXNAMELEN); 1489*da6c28aaSamw 1490*da6c28aaSamw return (error); 1491*da6c28aaSamw } 1492*da6c28aaSamw 1493*da6c28aaSamw int 1494*da6c28aaSamw smb_vop_lookup_xattrdir(vnode_t *fvp, vnode_t **xattrdirvpp, int flags, 1495*da6c28aaSamw cred_t *cr, caller_context_t *ct) 1496*da6c28aaSamw { 1497*da6c28aaSamw int error; 1498*da6c28aaSamw 1499*da6c28aaSamw error = VOP_LOOKUP(fvp, "", xattrdirvpp, NULL, flags, NULL, cr, ct, 1500*da6c28aaSamw NULL, NULL); 1501*da6c28aaSamw return (error); 1502*da6c28aaSamw } 1503*da6c28aaSamw 1504*da6c28aaSamw /* 1505*da6c28aaSamw * smb_vop_traverse_check() 1506*da6c28aaSamw * 1507*da6c28aaSamw * This function checks to see if the passed-in vnode has a file system 1508*da6c28aaSamw * mounted on it. If it does, the mount point is "traversed" and the 1509*da6c28aaSamw * vnode for the root of the file system is returned. 1510*da6c28aaSamw */ 1511*da6c28aaSamw 1512*da6c28aaSamw int 1513*da6c28aaSamw smb_vop_traverse_check(vnode_t **vpp) 1514*da6c28aaSamw { 1515*da6c28aaSamw int error; 1516*da6c28aaSamw 1517*da6c28aaSamw if (vn_mountedvfs(*vpp) == 0) 1518*da6c28aaSamw return (0); 1519*da6c28aaSamw 1520*da6c28aaSamw /* 1521*da6c28aaSamw * traverse() may return a different held vnode, even in the error case. 1522*da6c28aaSamw * If it returns a different vnode, it will have released the original. 1523*da6c28aaSamw */ 1524*da6c28aaSamw 1525*da6c28aaSamw error = traverse(vpp); 1526*da6c28aaSamw 1527*da6c28aaSamw return (error); 1528*da6c28aaSamw } 1529*da6c28aaSamw 1530*da6c28aaSamw int /*ARGSUSED*/ 1531*da6c28aaSamw smb_vop_statfs(vnode_t *vp, struct statvfs64 *statp, cred_t *cr) 1532*da6c28aaSamw { 1533*da6c28aaSamw int error; 1534*da6c28aaSamw 1535*da6c28aaSamw error = VFS_STATVFS(vp->v_vfsp, statp); 1536*da6c28aaSamw 1537*da6c28aaSamw return (error); 1538*da6c28aaSamw } 1539*da6c28aaSamw 1540*da6c28aaSamw /* 1541*da6c28aaSamw * smb_vop_acl_from_vsa 1542*da6c28aaSamw * 1543*da6c28aaSamw * Converts given vsecattr_t structure to a acl_t structure. 1544*da6c28aaSamw * 1545*da6c28aaSamw * The allocated memory for retuned acl_t should be freed by 1546*da6c28aaSamw * calling acl_free(). 1547*da6c28aaSamw */ 1548*da6c28aaSamw static acl_t * 1549*da6c28aaSamw smb_vop_acl_from_vsa(vsecattr_t *vsecattr, acl_type_t acl_type) 1550*da6c28aaSamw { 1551*da6c28aaSamw int aclbsize = 0; /* size of acl list in bytes */ 1552*da6c28aaSamw int dfaclbsize = 0; /* size of default acl list in bytes */ 1553*da6c28aaSamw int numacls; 1554*da6c28aaSamw acl_t *acl_info; 1555*da6c28aaSamw 1556*da6c28aaSamw ASSERT(vsecattr); 1557*da6c28aaSamw 1558*da6c28aaSamw acl_info = acl_alloc(acl_type); 1559*da6c28aaSamw if (acl_info == NULL) 1560*da6c28aaSamw return (NULL); 1561*da6c28aaSamw 1562*da6c28aaSamw acl_info->acl_flags = 0; 1563*da6c28aaSamw 1564*da6c28aaSamw switch (acl_type) { 1565*da6c28aaSamw 1566*da6c28aaSamw case ACLENT_T: 1567*da6c28aaSamw numacls = vsecattr->vsa_aclcnt + vsecattr->vsa_dfaclcnt; 1568*da6c28aaSamw aclbsize = vsecattr->vsa_aclcnt * sizeof (aclent_t); 1569*da6c28aaSamw dfaclbsize = vsecattr->vsa_dfaclcnt * sizeof (aclent_t); 1570*da6c28aaSamw 1571*da6c28aaSamw acl_info->acl_cnt = numacls; 1572*da6c28aaSamw acl_info->acl_aclp = kmem_alloc(aclbsize + dfaclbsize, 1573*da6c28aaSamw KM_SLEEP); 1574*da6c28aaSamw (void) memcpy(acl_info->acl_aclp, vsecattr->vsa_aclentp, 1575*da6c28aaSamw aclbsize); 1576*da6c28aaSamw (void) memcpy((char *)acl_info->acl_aclp + aclbsize, 1577*da6c28aaSamw vsecattr->vsa_dfaclentp, dfaclbsize); 1578*da6c28aaSamw 1579*da6c28aaSamw if (acl_info->acl_cnt <= MIN_ACL_ENTRIES) 1580*da6c28aaSamw acl_info->acl_flags |= ACL_IS_TRIVIAL; 1581*da6c28aaSamw 1582*da6c28aaSamw break; 1583*da6c28aaSamw 1584*da6c28aaSamw case ACE_T: 1585*da6c28aaSamw aclbsize = vsecattr->vsa_aclcnt * sizeof (ace_t); 1586*da6c28aaSamw acl_info->acl_cnt = vsecattr->vsa_aclcnt; 1587*da6c28aaSamw acl_info->acl_flags = vsecattr->vsa_aclflags; 1588*da6c28aaSamw acl_info->acl_aclp = kmem_alloc(aclbsize, KM_SLEEP); 1589*da6c28aaSamw (void) memcpy(acl_info->acl_aclp, vsecattr->vsa_aclentp, 1590*da6c28aaSamw aclbsize); 1591*da6c28aaSamw if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0) 1592*da6c28aaSamw acl_info->acl_flags |= ACL_IS_TRIVIAL; 1593*da6c28aaSamw 1594*da6c28aaSamw break; 1595*da6c28aaSamw 1596*da6c28aaSamw default: 1597*da6c28aaSamw acl_free(acl_info); 1598*da6c28aaSamw return (NULL); 1599*da6c28aaSamw } 1600*da6c28aaSamw 1601*da6c28aaSamw if (aclbsize && vsecattr->vsa_aclentp) 1602*da6c28aaSamw kmem_free(vsecattr->vsa_aclentp, aclbsize); 1603*da6c28aaSamw if (dfaclbsize && vsecattr->vsa_dfaclentp) 1604*da6c28aaSamw kmem_free(vsecattr->vsa_dfaclentp, dfaclbsize); 1605*da6c28aaSamw 1606*da6c28aaSamw return (acl_info); 1607*da6c28aaSamw } 1608*da6c28aaSamw 1609*da6c28aaSamw /* 1610*da6c28aaSamw * smb_vop_acl_to_vsa 1611*da6c28aaSamw * 1612*da6c28aaSamw * Converts given acl_t structure to a vsecattr_t structure. 1613*da6c28aaSamw * 1614*da6c28aaSamw * IMPORTANT: 1615*da6c28aaSamw * Upon successful return the memory allocated for vsa_aclentp 1616*da6c28aaSamw * should be freed by calling kmem_free(). The size is returned 1617*da6c28aaSamw * in aclbsize. 1618*da6c28aaSamw */ 1619*da6c28aaSamw int 1620*da6c28aaSamw smb_vop_acl_to_vsa(acl_t *acl_info, vsecattr_t *vsecattr, int *aclbsize) 1621*da6c28aaSamw { 1622*da6c28aaSamw int error = 0; 1623*da6c28aaSamw int numacls; 1624*da6c28aaSamw aclent_t *aclp; 1625*da6c28aaSamw 1626*da6c28aaSamw ASSERT(acl_info); 1627*da6c28aaSamw ASSERT(vsecattr); 1628*da6c28aaSamw ASSERT(aclbsize); 1629*da6c28aaSamw 1630*da6c28aaSamw bzero(vsecattr, sizeof (vsecattr_t)); 1631*da6c28aaSamw *aclbsize = 0; 1632*da6c28aaSamw 1633*da6c28aaSamw switch (acl_info->acl_type) { 1634*da6c28aaSamw case ACLENT_T: 1635*da6c28aaSamw numacls = acl_info->acl_cnt; 1636*da6c28aaSamw /* 1637*da6c28aaSamw * Minimum ACL size is three entries so might as well 1638*da6c28aaSamw * bail out here. Also limit request size to prevent user 1639*da6c28aaSamw * from allocating too much kernel memory. Maximum size 1640*da6c28aaSamw * is MAX_ACL_ENTRIES for the ACL part and MAX_ACL_ENTRIES 1641*da6c28aaSamw * for the default ACL part. 1642*da6c28aaSamw */ 1643*da6c28aaSamw if (numacls < 3 || numacls > (MAX_ACL_ENTRIES * 2)) { 1644*da6c28aaSamw error = EINVAL; 1645*da6c28aaSamw break; 1646*da6c28aaSamw } 1647*da6c28aaSamw 1648*da6c28aaSamw vsecattr->vsa_mask = VSA_ACL; 1649*da6c28aaSamw 1650*da6c28aaSamw vsecattr->vsa_aclcnt = numacls; 1651*da6c28aaSamw *aclbsize = numacls * sizeof (aclent_t); 1652*da6c28aaSamw vsecattr->vsa_aclentp = kmem_alloc(*aclbsize, KM_SLEEP); 1653*da6c28aaSamw (void) memcpy(vsecattr->vsa_aclentp, acl_info->acl_aclp, 1654*da6c28aaSamw *aclbsize); 1655*da6c28aaSamw 1656*da6c28aaSamw /* Sort the acl list */ 1657*da6c28aaSamw ksort((caddr_t)vsecattr->vsa_aclentp, 1658*da6c28aaSamw vsecattr->vsa_aclcnt, sizeof (aclent_t), cmp2acls); 1659*da6c28aaSamw 1660*da6c28aaSamw /* Break into acl and default acl lists */ 1661*da6c28aaSamw for (numacls = 0, aclp = vsecattr->vsa_aclentp; 1662*da6c28aaSamw numacls < vsecattr->vsa_aclcnt; 1663*da6c28aaSamw aclp++, numacls++) { 1664*da6c28aaSamw if (aclp->a_type & ACL_DEFAULT) 1665*da6c28aaSamw break; 1666*da6c28aaSamw } 1667*da6c28aaSamw 1668*da6c28aaSamw /* Find where defaults start (if any) */ 1669*da6c28aaSamw if (numacls < vsecattr->vsa_aclcnt) { 1670*da6c28aaSamw vsecattr->vsa_mask |= VSA_DFACL; 1671*da6c28aaSamw vsecattr->vsa_dfaclcnt = vsecattr->vsa_aclcnt - numacls; 1672*da6c28aaSamw vsecattr->vsa_dfaclentp = aclp; 1673*da6c28aaSamw vsecattr->vsa_aclcnt = numacls; 1674*da6c28aaSamw } 1675*da6c28aaSamw 1676*da6c28aaSamw /* Adjust if they're all defaults */ 1677*da6c28aaSamw if (vsecattr->vsa_aclcnt == 0) { 1678*da6c28aaSamw vsecattr->vsa_mask &= ~VSA_ACL; 1679*da6c28aaSamw vsecattr->vsa_aclentp = NULL; 1680*da6c28aaSamw } 1681*da6c28aaSamw 1682*da6c28aaSamw /* Only directories can have defaults */ 1683*da6c28aaSamw if (vsecattr->vsa_dfaclcnt && 1684*da6c28aaSamw (acl_info->acl_flags & ACL_IS_DIR)) { 1685*da6c28aaSamw error = ENOTDIR; 1686*da6c28aaSamw } 1687*da6c28aaSamw 1688*da6c28aaSamw break; 1689*da6c28aaSamw 1690*da6c28aaSamw case ACE_T: 1691*da6c28aaSamw if (acl_info->acl_cnt < 1 || 1692*da6c28aaSamw acl_info->acl_cnt > MAX_ACL_ENTRIES) { 1693*da6c28aaSamw error = EINVAL; 1694*da6c28aaSamw break; 1695*da6c28aaSamw } 1696*da6c28aaSamw 1697*da6c28aaSamw vsecattr->vsa_mask = VSA_ACE | VSA_ACE_ACLFLAGS; 1698*da6c28aaSamw vsecattr->vsa_aclcnt = acl_info->acl_cnt; 1699*da6c28aaSamw vsecattr->vsa_aclflags = acl_info->acl_flags & ACL_FLAGS_ALL; 1700*da6c28aaSamw *aclbsize = vsecattr->vsa_aclcnt * sizeof (ace_t); 1701*da6c28aaSamw vsecattr->vsa_aclentsz = *aclbsize; 1702*da6c28aaSamw vsecattr->vsa_aclentp = kmem_alloc(*aclbsize, KM_SLEEP); 1703*da6c28aaSamw (void) memcpy(vsecattr->vsa_aclentp, acl_info->acl_aclp, 1704*da6c28aaSamw *aclbsize); 1705*da6c28aaSamw 1706*da6c28aaSamw break; 1707*da6c28aaSamw 1708*da6c28aaSamw default: 1709*da6c28aaSamw error = EINVAL; 1710*da6c28aaSamw } 1711*da6c28aaSamw 1712*da6c28aaSamw return (error); 1713*da6c28aaSamw } 1714*da6c28aaSamw 1715*da6c28aaSamw /* 1716*da6c28aaSamw * smb_vop_acl_read 1717*da6c28aaSamw * 1718*da6c28aaSamw * Reads the ACL of the specified file into 'aclp'. 1719*da6c28aaSamw * acl_type is the type of ACL which the filesystem supports. 1720*da6c28aaSamw * 1721*da6c28aaSamw * Caller has to free the allocated memory for aclp by calling 1722*da6c28aaSamw * acl_free(). 1723*da6c28aaSamw */ 1724*da6c28aaSamw int 1725*da6c28aaSamw smb_vop_acl_read(vnode_t *vp, acl_t **aclp, int flags, acl_type_t acl_type, 1726*da6c28aaSamw cred_t *cr, caller_context_t *ct) 1727*da6c28aaSamw { 1728*da6c28aaSamw int error; 1729*da6c28aaSamw vsecattr_t vsecattr; 1730*da6c28aaSamw 1731*da6c28aaSamw ASSERT(vp); 1732*da6c28aaSamw ASSERT(aclp); 1733*da6c28aaSamw 1734*da6c28aaSamw *aclp = NULL; 1735*da6c28aaSamw bzero(&vsecattr, sizeof (vsecattr_t)); 1736*da6c28aaSamw 1737*da6c28aaSamw switch (acl_type) { 1738*da6c28aaSamw case ACLENT_T: 1739*da6c28aaSamw vsecattr.vsa_mask = VSA_ACL | VSA_ACLCNT | VSA_DFACL | 1740*da6c28aaSamw VSA_DFACLCNT; 1741*da6c28aaSamw break; 1742*da6c28aaSamw 1743*da6c28aaSamw case ACE_T: 1744*da6c28aaSamw vsecattr.vsa_mask = VSA_ACE | VSA_ACECNT | VSA_ACE_ACLFLAGS; 1745*da6c28aaSamw break; 1746*da6c28aaSamw 1747*da6c28aaSamw default: 1748*da6c28aaSamw return (EINVAL); 1749*da6c28aaSamw } 1750*da6c28aaSamw 1751*da6c28aaSamw if (error = VOP_GETSECATTR(vp, &vsecattr, flags, cr, ct)) 1752*da6c28aaSamw return (error); 1753*da6c28aaSamw 1754*da6c28aaSamw *aclp = smb_vop_acl_from_vsa(&vsecattr, acl_type); 1755*da6c28aaSamw if (vp->v_type == VDIR) 1756*da6c28aaSamw (*aclp)->acl_flags |= ACL_IS_DIR; 1757*da6c28aaSamw 1758*da6c28aaSamw return (0); 1759*da6c28aaSamw } 1760*da6c28aaSamw 1761*da6c28aaSamw /* 1762*da6c28aaSamw * smb_vop_acl_write 1763*da6c28aaSamw * 1764*da6c28aaSamw * Writes the given ACL in aclp for the specified file. 1765*da6c28aaSamw */ 1766*da6c28aaSamw int 1767*da6c28aaSamw smb_vop_acl_write(vnode_t *vp, acl_t *aclp, int flags, cred_t *cr, 1768*da6c28aaSamw caller_context_t *ct) 1769*da6c28aaSamw { 1770*da6c28aaSamw int error; 1771*da6c28aaSamw vsecattr_t vsecattr; 1772*da6c28aaSamw int aclbsize; 1773*da6c28aaSamw 1774*da6c28aaSamw ASSERT(vp); 1775*da6c28aaSamw ASSERT(aclp); 1776*da6c28aaSamw 1777*da6c28aaSamw error = smb_vop_acl_to_vsa(aclp, &vsecattr, &aclbsize); 1778*da6c28aaSamw 1779*da6c28aaSamw if (error == 0) { 1780*da6c28aaSamw (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); 1781*da6c28aaSamw error = VOP_SETSECATTR(vp, &vsecattr, flags, cr, ct); 1782*da6c28aaSamw VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 1783*da6c28aaSamw } 1784*da6c28aaSamw 1785*da6c28aaSamw if (aclbsize && vsecattr.vsa_aclentp) 1786*da6c28aaSamw kmem_free(vsecattr.vsa_aclentp, aclbsize); 1787*da6c28aaSamw 1788*da6c28aaSamw return (error); 1789*da6c28aaSamw } 1790*da6c28aaSamw 1791*da6c28aaSamw /* 1792*da6c28aaSamw * smb_vop_acl_type 1793*da6c28aaSamw * 1794*da6c28aaSamw * Determines the ACL type for the given vnode. 1795*da6c28aaSamw * ACLENT_T is a Posix ACL and ACE_T is a ZFS ACL. 1796*da6c28aaSamw */ 1797*da6c28aaSamw acl_type_t 1798*da6c28aaSamw smb_vop_acl_type(vnode_t *vp) 1799*da6c28aaSamw { 1800*da6c28aaSamw int error; 1801*da6c28aaSamw ulong_t whichacl; 1802*da6c28aaSamw 1803*da6c28aaSamw error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &whichacl, kcred, NULL); 1804*da6c28aaSamw if (error != 0) { 1805*da6c28aaSamw /* 1806*da6c28aaSamw * If we got an error, then the filesystem 1807*da6c28aaSamw * likely does not understand the _PC_ACL_ENABLED 1808*da6c28aaSamw * pathconf. In this case, we fall back to trying 1809*da6c28aaSamw * POSIX-draft (aka UFS-style) ACLs. 1810*da6c28aaSamw */ 1811*da6c28aaSamw whichacl = _ACL_ACLENT_ENABLED; 1812*da6c28aaSamw } 1813*da6c28aaSamw 1814*da6c28aaSamw if (!(whichacl & (_ACL_ACE_ENABLED | _ACL_ACLENT_ENABLED))) { 1815*da6c28aaSamw /* 1816*da6c28aaSamw * If the file system supports neither ACE nor 1817*da6c28aaSamw * ACLENT ACLs we will fall back to UFS-style ACLs 1818*da6c28aaSamw * like we did above if there was an error upon 1819*da6c28aaSamw * calling VOP_PATHCONF. 1820*da6c28aaSamw * 1821*da6c28aaSamw * ACE and ACLENT type ACLs are the only interfaces 1822*da6c28aaSamw * supported thus far. If any other bits are set on 1823*da6c28aaSamw * 'whichacl' upon return from VOP_PATHCONF, we will 1824*da6c28aaSamw * ignore them. 1825*da6c28aaSamw */ 1826*da6c28aaSamw whichacl = _ACL_ACLENT_ENABLED; 1827*da6c28aaSamw } 1828*da6c28aaSamw 1829*da6c28aaSamw if (whichacl == _ACL_ACLENT_ENABLED) 1830*da6c28aaSamw return (ACLENT_T); 1831*da6c28aaSamw 1832*da6c28aaSamw return (ACE_T); 1833*da6c28aaSamw } 1834*da6c28aaSamw 1835*da6c28aaSamw static int zfs_perms[] = { 1836*da6c28aaSamw ACE_READ_DATA, ACE_WRITE_DATA, ACE_APPEND_DATA, ACE_READ_NAMED_ATTRS, 1837*da6c28aaSamw ACE_WRITE_NAMED_ATTRS, ACE_EXECUTE, ACE_DELETE_CHILD, 1838*da6c28aaSamw ACE_READ_ATTRIBUTES, ACE_WRITE_ATTRIBUTES, ACE_DELETE, ACE_READ_ACL, 1839*da6c28aaSamw ACE_WRITE_ACL, ACE_WRITE_OWNER, ACE_SYNCHRONIZE 1840*da6c28aaSamw }; 1841*da6c28aaSamw 1842*da6c28aaSamw static int unix_perms[] = { VREAD, VWRITE, VEXEC }; 1843*da6c28aaSamw /* 1844*da6c28aaSamw * smb_vop_eaccess 1845*da6c28aaSamw * 1846*da6c28aaSamw * Returns the effective permission of the given credential for the 1847*da6c28aaSamw * specified object. 1848*da6c28aaSamw * 1849*da6c28aaSamw * This is just a workaround. We need VFS/FS support for this. 1850*da6c28aaSamw */ 1851*da6c28aaSamw void 1852*da6c28aaSamw smb_vop_eaccess(vnode_t *vp, int *mode, int flags, vnode_t *dir_vp, cred_t *cr) 1853*da6c28aaSamw { 1854*da6c28aaSamw int error, i; 1855*da6c28aaSamw int pnum; 1856*da6c28aaSamw 1857*da6c28aaSamw *mode = 0; 1858*da6c28aaSamw 1859*da6c28aaSamw if (flags == V_ACE_MASK) { 1860*da6c28aaSamw pnum = sizeof (zfs_perms) / sizeof (int); 1861*da6c28aaSamw 1862*da6c28aaSamw for (i = 0; i < pnum; i++) { 1863*da6c28aaSamw error = smb_vop_access(vp, zfs_perms[i], flags, 1864*da6c28aaSamw dir_vp, cr); 1865*da6c28aaSamw if (error == 0) 1866*da6c28aaSamw *mode |= zfs_perms[i]; 1867*da6c28aaSamw } 1868*da6c28aaSamw } else { 1869*da6c28aaSamw pnum = sizeof (unix_perms) / sizeof (int); 1870*da6c28aaSamw 1871*da6c28aaSamw for (i = 0; i < pnum; i++) { 1872*da6c28aaSamw error = smb_vop_access(vp, unix_perms[i], flags, 1873*da6c28aaSamw dir_vp, cr); 1874*da6c28aaSamw if (error == 0) 1875*da6c28aaSamw *mode |= unix_perms[i]; 1876*da6c28aaSamw } 1877*da6c28aaSamw } 1878*da6c28aaSamw } 1879