15331Samw /* 25331Samw * CDDL HEADER START 35331Samw * 45331Samw * The contents of this file are subject to the terms of the 55331Samw * Common Development and Distribution License (the "License"). 65331Samw * You may not use this file except in compliance with the License. 75331Samw * 85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95331Samw * or http://www.opensolaris.org/os/licensing. 105331Samw * See the License for the specific language governing permissions 115331Samw * and limitations under the License. 125331Samw * 135331Samw * When distributing Covered Code, include this CDDL HEADER in each 145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155331Samw * If applicable, add the following below this CDDL HEADER, with the 165331Samw * fields enclosed by brackets "[]" replaced with your own identifying 175331Samw * information: Portions Copyright [yyyy] [name of copyright owner] 185331Samw * 195331Samw * CDDL HEADER END 205331Samw */ 215331Samw /* 225331Samw * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 235331Samw * Use is subject to license terms. 245331Samw */ 255331Samw 265331Samw #pragma ident "%Z%%M% %I% %E% SMI" 275331Samw 285331Samw #include <sys/types.h> 295331Samw #include <sys/stat.h> 305331Samw #include <sys/uio.h> 315331Samw #include <sys/statvfs.h> 325331Samw #include <sys/vnode.h> 335331Samw #include <sys/thread.h> 345331Samw #include <sys/pathname.h> 355331Samw #include <sys/cred.h> 365331Samw #include <sys/extdirent.h> 37*5521Sas200622 385331Samw #include <smbsrv/smb_vops.h> 395331Samw #include <smbsrv/string.h> 40*5521Sas200622 415331Samw #include <smbsrv/smbtrans.h> 42*5521Sas200622 #include <smbsrv/smb_fsops.h> 43*5521Sas200622 #include <smbsrv/smb_kproto.h> 445331Samw #include <smbsrv/smb_incl.h> 45*5521Sas200622 465331Samw 475331Samw static int 485331Samw smb_vop_readdir_readpage(vnode_t *vp, void *buf, uint32_t offset, int *count, 495331Samw cred_t *cr, caller_context_t *ct, int flags); 505331Samw 515331Samw static int 525331Samw smb_vop_readdir_entry(vnode_t *dvp, uint32_t *cookiep, char *name, int *namelen, 535331Samw ino64_t *inop, vnode_t **vpp, char *od_name, int flags, cred_t *cr, 545331Samw caller_context_t *ct, char *dirbuf, int num_bytes); 555331Samw 565331Samw static int 575331Samw smb_vop_getdents_entries(smb_node_t *dir_snode, uint32_t *cookiep, 585331Samw int32_t *dircountp, char *arg, uint32_t flags, struct smb_request *sr, 595331Samw cred_t *cr, caller_context_t *ct, char *dirbuf, int *maxentries, 605331Samw int num_bytes, char *); 615331Samw 625331Samw extern int 635331Samw smb_gather_dents_info(char *args, ino_t fileid, int namelen, 645331Samw char *name, uint32_t cookie, int32_t *countp, 655331Samw smb_attr_t *attr, struct smb_node *snode, 665331Samw char *shortname, char *name83); 675331Samw 685331Samw static void 695331Samw smb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp); 705331Samw 715331Samw #define SMB_AT_MAX 16 725331Samw static uint_t smb_attrmap[SMB_AT_MAX] = { 735331Samw 0, 745331Samw AT_TYPE, 755331Samw AT_MODE, 765331Samw AT_UID, 775331Samw AT_GID, 785331Samw AT_FSID, 795331Samw AT_NODEID, 805331Samw AT_NLINK, 815331Samw AT_SIZE, 825331Samw AT_ATIME, 835331Samw AT_MTIME, 845331Samw AT_CTIME, 855331Samw AT_RDEV, 865331Samw AT_BLKSIZE, 875331Samw AT_NBLOCKS, 885331Samw AT_SEQ 895331Samw }; 905331Samw 915331Samw int 925331Samw smb_vop_open(vnode_t **vpp, int mode, cred_t *cred, caller_context_t *ct) 935331Samw { 945331Samw return (VOP_OPEN(vpp, mode, cred, ct)); 955331Samw } 965331Samw 975331Samw int 985331Samw smb_vop_close(vnode_t *vp, int mode, cred_t *cred, caller_context_t *ct) 995331Samw { 1005331Samw return (VOP_CLOSE(vp, mode, 1, (offset_t)0, cred, ct)); 1015331Samw } 1025331Samw 1035331Samw /* 1045331Samw * The smb_vop_* functions have minimal knowledge of CIFS semantics and 1055331Samw * serve as an interface to the VFS layer. 1065331Samw * 1075331Samw * Only smb_fsop_* layer functions should call smb_vop_* layer functions. 1085331Samw * (Higher-level CIFS service code should never skip the smb_fsop_* layer 1095331Samw * to call smb_vop_* layer functions directly.) 1105331Samw */ 1115331Samw 1125331Samw /* 1135331Samw * XXX - Extended attributes support in the file system assumed. 1145331Samw * This is needed for full NT Streams functionality. 1155331Samw */ 1165331Samw 1175331Samw int 1185331Samw smb_vop_read(vnode_t *vp, uio_t *uiop, cred_t *cr, caller_context_t *ct) 1195331Samw { 1205331Samw int error; 1215331Samw 1225331Samw (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL); 1235331Samw error = VOP_READ(vp, uiop, 0, cr, ct); 1245331Samw VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 1255331Samw return (error); 1265331Samw } 1275331Samw 1285331Samw int 1295331Samw smb_vop_write(vnode_t *vp, uio_t *uiop, uint32_t *flag, uint32_t *lcount, 1305331Samw cred_t *cr, caller_context_t *ct) 1315331Samw { 1325331Samw int error; 1335331Samw int ioflag = 0; 1345331Samw 1355331Samw *lcount = uiop->uio_resid; 1365331Samw 1375331Samw if (*flag == FSSTAB_FILE_SYNC) 1385331Samw ioflag = FSYNC; 1395331Samw 1405331Samw uiop->uio_llimit = MAXOFFSET_T; 1415331Samw 1425331Samw (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); 1435331Samw error = VOP_WRITE(vp, uiop, ioflag, cr, ct); 1445331Samw VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 1455331Samw 1465331Samw *lcount -= uiop->uio_resid; 1475331Samw 1485331Samw return (error); 1495331Samw } 1505331Samw 1515331Samw /* 1525331Samw * smb_vop_getattr() 1535331Samw * 1545331Samw * smb_fsop_getattr()/smb_vop_getattr() should always be called from the CIFS 1555331Samw * service (instead of calling VOP_GETATTR directly) to retrieve attributes 1565331Samw * due to special processing needed for streams files. 1575331Samw * 1585331Samw * All attributes are retrieved. 1595331Samw * 1605331Samw * A named stream's attributes (as far as CIFS is concerned) are those of the 1615331Samw * unnamed (i.e. data) stream (minus the size attribute), and the size of the 1625331Samw * named stream. Though the file system may store attributes other than size 1635331Samw * with the named stream, these should not be used by CIFS for any purpose. 1645331Samw * 1655331Samw * When vp denotes a named stream, then unnamed_vp should be passed in (denoting 1665331Samw * the corresponding unnamed stream). 1675331Samw */ 1685331Samw 1695331Samw int 1705331Samw smb_vop_getattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *ret_attr, 1715331Samw int flags, cred_t *cr, caller_context_t *ct) 1725331Samw { 1735331Samw int error; 1745331Samw vnode_t *use_vp; 1755331Samw smb_attr_t tmp_attr; 1765331Samw xvattr_t tmp_xvattr; 1775331Samw xoptattr_t *xoap = NULL; 1785331Samw 1795331Samw if (unnamed_vp) 1805331Samw use_vp = unnamed_vp; 1815331Samw else 1825331Samw use_vp = vp; 1835331Samw 1845331Samw if (vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) { 1855331Samw xva_init(&tmp_xvattr); 1865331Samw xoap = xva_getxoptattr(&tmp_xvattr); 1875331Samw 1885331Samw ASSERT(xoap); 1895331Samw 1905331Samw smb_sa_to_va_mask(ret_attr->sa_mask, 1915331Samw &tmp_xvattr.xva_vattr.va_mask); 1925331Samw 1935331Samw XVA_SET_REQ(&tmp_xvattr, XAT_READONLY); 1945331Samw XVA_SET_REQ(&tmp_xvattr, XAT_HIDDEN); 1955331Samw XVA_SET_REQ(&tmp_xvattr, XAT_SYSTEM); 1965331Samw XVA_SET_REQ(&tmp_xvattr, XAT_ARCHIVE); 1975331Samw XVA_SET_REQ(&tmp_xvattr, XAT_CREATETIME); 1985331Samw 1995331Samw if ((error = VOP_GETATTR(use_vp, (vattr_t *)&tmp_xvattr, flags, 2005331Samw cr, ct)) != 0) 2015331Samw return (error); 2025331Samw 2035331Samw ret_attr->sa_vattr = tmp_xvattr.xva_vattr; 2045331Samw 2055331Samw /* 2065331Samw * Copy special attributes to ret_attr parameter 2075331Samw */ 2085331Samw 2095331Samw ret_attr->sa_dosattr = 0; 2105331Samw 2115331Samw ASSERT(tmp_xvattr.xva_vattr.va_mask & AT_XVATTR); 2125331Samw 2135331Samw xoap = xva_getxoptattr(&tmp_xvattr); 2145331Samw ASSERT(xoap); 2155331Samw 2165331Samw if (XVA_ISSET_RTN(&tmp_xvattr, XAT_READONLY)) { 2175331Samw if (xoap->xoa_readonly) 2185331Samw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_READONLY; 2195331Samw } 2205331Samw 2215331Samw if (XVA_ISSET_RTN(&tmp_xvattr, XAT_HIDDEN)) { 2225331Samw if (xoap->xoa_hidden) 2235331Samw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_HIDDEN; 2245331Samw } 2255331Samw 2265331Samw if (XVA_ISSET_RTN(&tmp_xvattr, XAT_SYSTEM)) { 2275331Samw if (xoap->xoa_system) 2285331Samw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_SYSTEM; 2295331Samw } 2305331Samw 2315331Samw if (XVA_ISSET_RTN(&tmp_xvattr, XAT_ARCHIVE)) { 2325331Samw if (xoap->xoa_archive) 2335331Samw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_ARCHIVE; 2345331Samw } 2355331Samw 2365331Samw ret_attr->sa_crtime = xoap->xoa_createtime; 2375331Samw 2385331Samw if (unnamed_vp && (ret_attr->sa_mask & SMB_AT_SIZE)) { 2395331Samw /* 2405331Samw * Retrieve stream size attribute into temporary 2415331Samw * structure, in case the underlying file system 2425331Samw * returns attributes other than the size (we do not 2435331Samw * want to have ret_attr's other fields get 2445331Samw * overwritten). 2455331Samw * 2465331Samw * Note that vp is used here, and not use_vp. 2475331Samw * Also, only AT_SIZE is needed. 2485331Samw */ 2495331Samw 2505331Samw tmp_xvattr.xva_vattr.va_mask = AT_SIZE; 2515331Samw 2525331Samw if ((error = VOP_GETATTR(vp, (vattr_t *)&tmp_xvattr, 2535331Samw flags, cr, ct)) != 0) 2545331Samw return (error); 2555331Samw 2565331Samw ret_attr->sa_vattr.va_size = 2575331Samw tmp_xvattr.xva_vattr.va_size; 2585331Samw 2595331Samw } 2605331Samw 2615331Samw if (ret_attr->sa_vattr.va_type == VDIR) { 2625331Samw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY; 2635331Samw } 2645331Samw 2655331Samw return (error); 2665331Samw } 2675331Samw 2685331Samw /* 2695331Samw * Support for file systems without VFSFT_XVATTR 2705331Samw */ 2715331Samw 2725331Samw smb_sa_to_va_mask(ret_attr->sa_mask, 2735331Samw &ret_attr->sa_vattr.va_mask); 2745331Samw 2755331Samw error = VOP_GETATTR(use_vp, &ret_attr->sa_vattr, flags, cr, ct); 2765331Samw 2775331Samw if (error != 0) 2785331Samw return (error); 2795331Samw 2805331Samw /* 2815331Samw * "Fake" DOS attributes and create time, filesystem doesn't support 2825331Samw * them. 2835331Samw */ 2845331Samw 2855331Samw ret_attr->sa_dosattr = 0; 2865331Samw ret_attr->sa_crtime = ret_attr->sa_vattr.va_ctime; 2875331Samw 2885331Samw if (unnamed_vp && (ret_attr->sa_mask & SMB_AT_SIZE)) { 2895331Samw /* 2905331Samw * Retrieve stream size attribute into temporary structure, 2915331Samw * in case the underlying file system returns attributes 2925331Samw * other than the size (we do not want to have ret_attr's 2935331Samw * other fields get overwritten). 2945331Samw * 2955331Samw * Note that vp is used here, and not use_vp. 2965331Samw * Also, only AT_SIZE is needed. 2975331Samw */ 2985331Samw 2995331Samw tmp_attr.sa_vattr.va_mask = AT_SIZE; 3005331Samw error = VOP_GETATTR(vp, &tmp_attr.sa_vattr, flags, cr, ct); 3015331Samw 3025331Samw if (error != 0) 3035331Samw return (error); 3045331Samw 3055331Samw 3065331Samw ret_attr->sa_vattr.va_size = tmp_attr.sa_vattr.va_size; 3075331Samw } 3085331Samw 3095331Samw if (ret_attr->sa_vattr.va_type == VDIR) { 3105331Samw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY; 3115331Samw } 3125331Samw 3135331Samw return (error); 3145331Samw } 3155331Samw 3165331Samw /* 3175331Samw * smb_vop_setattr() 3185331Samw * 3195331Samw * smb_fsop_setattr()/smb_vop_setattr() should always be called from the CIFS 3205331Samw * service to set attributes due to special processing for streams files. 3215331Samw * 3225331Samw * When smb_vop_setattr() is called on a named stream file, all indicated 3235331Samw * attributes except the size are set on the unnamed stream file. The size 3245331Samw * (if indicated) is set on the named stream file. 3255331Samw */ 3265331Samw 3275331Samw int 3285331Samw smb_vop_setattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *set_attr, 329*5521Sas200622 int flags, cred_t *cr, boolean_t no_xvattr, caller_context_t *ct) 3305331Samw { 3315331Samw int error = 0; 3325331Samw int at_size = 0; 3335331Samw vnode_t *use_vp; 3345331Samw xvattr_t tmp_xvattr; 3355331Samw xoptattr_t *xoap = NULL; 3365331Samw uint_t xva_mask; 3375331Samw 3385331Samw if (unnamed_vp) { 3395331Samw use_vp = unnamed_vp; 3405331Samw if (set_attr->sa_mask & SMB_AT_SIZE) { 3415331Samw at_size = 1; 3425331Samw set_attr->sa_mask &= ~SMB_AT_SIZE; 3435331Samw } 3445331Samw } else { 3455331Samw use_vp = vp; 3465331Samw } 3475331Samw 3485331Samw /* 3495331Samw * The caller should not be setting sa_vattr.va_mask, 3505331Samw * but rather sa_mask. 3515331Samw */ 3525331Samw 3535331Samw set_attr->sa_vattr.va_mask = 0; 3545331Samw 355*5521Sas200622 if ((no_xvattr == B_FALSE) && 356*5521Sas200622 vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) { 3575331Samw /* 3585331Samw * Initialize xvattr, including bzero 3595331Samw */ 3605331Samw xva_init(&tmp_xvattr); 3615331Samw xoap = xva_getxoptattr(&tmp_xvattr); 3625331Samw 3635331Samw ASSERT(xoap); 3645331Samw 3655331Samw /* 3665331Samw * Copy caller-specified classic attributes to tmp_xvattr. 367*5521Sas200622 * First save tmp_xvattr's mask (set in xva_init()), which 368*5521Sas200622 * contains AT_XVATTR. This is |'d in later if needed. 3695331Samw */ 3705331Samw 3715331Samw xva_mask = tmp_xvattr.xva_vattr.va_mask; 3725331Samw tmp_xvattr.xva_vattr = set_attr->sa_vattr; 3735331Samw 3745331Samw smb_sa_to_va_mask(set_attr->sa_mask, 3755331Samw &tmp_xvattr.xva_vattr.va_mask); 3765331Samw 3775331Samw /* 378*5521Sas200622 * Do not set ctime (only the file system can do it) 3795331Samw */ 3805331Samw 381*5521Sas200622 tmp_xvattr.xva_vattr.va_mask &= ~AT_CTIME; 3825331Samw 3835331Samw if (set_attr->sa_mask & SMB_AT_DOSATTR) { 384*5521Sas200622 385*5521Sas200622 /* 386*5521Sas200622 * "|" in the original xva_mask, which contains 387*5521Sas200622 * AT_XVATTR 388*5521Sas200622 */ 389*5521Sas200622 390*5521Sas200622 tmp_xvattr.xva_vattr.va_mask |= xva_mask; 391*5521Sas200622 3925331Samw XVA_SET_REQ(&tmp_xvattr, XAT_ARCHIVE); 3935331Samw XVA_SET_REQ(&tmp_xvattr, XAT_SYSTEM); 3945331Samw XVA_SET_REQ(&tmp_xvattr, XAT_READONLY); 3955331Samw XVA_SET_REQ(&tmp_xvattr, XAT_HIDDEN); 3965331Samw 3975331Samw /* 3985331Samw * set_attr->sa_dosattr: If a given bit is not set, 3995331Samw * that indicates that the corresponding field needs 4005331Samw * to be updated with a "0" value. This is done 4015331Samw * implicitly as the xoap->xoa_* fields were bzero'd. 4025331Samw */ 4035331Samw 4045331Samw if (set_attr->sa_dosattr & FILE_ATTRIBUTE_ARCHIVE) 4055331Samw xoap->xoa_archive = 1; 4065331Samw 4075331Samw if (set_attr->sa_dosattr & FILE_ATTRIBUTE_SYSTEM) 4085331Samw xoap->xoa_system = 1; 4095331Samw 4105331Samw if (set_attr->sa_dosattr & FILE_ATTRIBUTE_READONLY) 4115331Samw xoap->xoa_readonly = 1; 4125331Samw 4135331Samw if (set_attr->sa_dosattr & FILE_ATTRIBUTE_HIDDEN) 4145331Samw xoap->xoa_hidden = 1; 4155331Samw } 4165331Samw 4175331Samw if (set_attr->sa_mask & SMB_AT_CRTIME) { 418*5521Sas200622 /* 419*5521Sas200622 * "|" in the original xva_mask, which contains 420*5521Sas200622 * AT_XVATTR 421*5521Sas200622 */ 422*5521Sas200622 423*5521Sas200622 tmp_xvattr.xva_vattr.va_mask |= xva_mask; 4245331Samw XVA_SET_REQ(&tmp_xvattr, XAT_CREATETIME); 4255331Samw xoap->xoa_createtime = set_attr->sa_crtime; 4265331Samw } 4275331Samw 4285331Samw if ((error = VOP_SETATTR(use_vp, (vattr_t *)&tmp_xvattr, flags, 4295331Samw cr, ct)) != 0) 4305331Samw return (error); 4315331Samw 4325331Samw /* 4335331Samw * If the size of the stream needs to be set, set it on 4345331Samw * the stream file directly. (All other indicated attributes 4355331Samw * are set on the stream's unnamed stream, above.) 4365331Samw */ 4375331Samw 4385331Samw if (at_size) { 4395331Samw /* 4405331Samw * set_attr->sa_vattr.va_size already contains the 4415331Samw * size as set by the caller 4425331Samw * 4435331Samw * Note that vp is used here, and not use_vp. 4445331Samw * Also, only AT_SIZE is needed. 4455331Samw */ 4465331Samw 4475331Samw set_attr->sa_vattr.va_mask = AT_SIZE; 4485331Samw error = VOP_SETATTR(vp, &set_attr->sa_vattr, flags, 4495331Samw cr, ct); 4505331Samw } 4515331Samw return (error); 4525331Samw } 4535331Samw /* 454*5521Sas200622 * Support for file systems without VFSFT_XVATTR or no_xvattr == B_TRUE 4555331Samw */ 4565331Samw smb_sa_to_va_mask(set_attr->sa_mask, &set_attr->sa_vattr.va_mask); 4575331Samw /* 4585331Samw * set_attr->sa_vattr already contains new values 4595331Samw * as set by the caller 4605331Samw */ 4615331Samw 4625331Samw error = VOP_SETATTR(use_vp, &set_attr->sa_vattr, flags, cr, ct); 4635331Samw 4645331Samw if (error != 0) 4655331Samw return (error); 4665331Samw 4675331Samw if (at_size) { 4685331Samw /* 4695331Samw * set_attr->sa_vattr.va_size already contains the 4705331Samw * size as set by the caller 4715331Samw * 4725331Samw * Note that vp is used here, and not use_vp. 4735331Samw * Also, only AT_SIZE is needed. 4745331Samw */ 4755331Samw 4765331Samw set_attr->sa_vattr.va_mask = AT_SIZE; 4775331Samw error = VOP_SETATTR(vp, &set_attr->sa_vattr, flags, cr, ct); 4785331Samw } 4795331Samw return (error); 4805331Samw } 4815331Samw 4825331Samw /* 4835331Samw * smb_vop_access 4845331Samw * 4855331Samw * This is a wrapper round VOP_ACCESS. VOP_ACCESS checks the given mode 4865331Samw * against file's ACL or Unix permissions. CIFS on the other hand needs to 4875331Samw * know if the requested operation can succeed for the given object, this 4885331Samw * requires more checks in case of DELETE bit since permissions on the parent 4895331Samw * directory are important as well. Based on Windows rules if parent's ACL 4905331Samw * grant FILE_DELETE_CHILD a file can be delete regardless of the file's 4915331Samw * permissions. 4925331Samw */ 4935331Samw int 4945331Samw smb_vop_access(vnode_t *vp, int mode, int flags, vnode_t *dir_vp, cred_t *cr) 4955331Samw { 4965331Samw int error = 0; 4975331Samw 4985331Samw if (mode == 0) 4995331Samw return (0); 5005331Samw 5015331Samw if ((flags == V_ACE_MASK) && (mode & ACE_DELETE)) { 5025331Samw if (dir_vp) { 5035331Samw error = VOP_ACCESS(dir_vp, ACE_DELETE_CHILD, flags, 5045331Samw cr, NULL); 5055331Samw 5065331Samw if (error == 0) 5075331Samw mode &= ~ACE_DELETE; 5085331Samw } 5095331Samw } 5105331Samw 5115331Samw if (mode) { 5125331Samw error = VOP_ACCESS(vp, mode, flags, cr, NULL); 5135331Samw } 5145331Samw 5155331Samw return (error); 5165331Samw } 5175331Samw 5185331Samw /* 5195331Samw * smb_vop_lookup 5205331Samw * 5215331Samw * dvp: directory vnode (in) 5225331Samw * name: name of file to be looked up (in) 5235331Samw * vpp: looked-up vnode (out) 5245331Samw * od_name: on-disk name of file (out). 5255331Samw * This parameter is optional. If a pointer is passed in, it 5265331Samw * must be allocated with MAXNAMELEN bytes 5275331Samw * rootvp: vnode of the tree root (in) 5285331Samw * This parameter is always passed in non-NULL except at the time 5295331Samw * of share set up. 5305331Samw */ 5315331Samw 5325331Samw int 5335331Samw smb_vop_lookup(vnode_t *dvp, char *name, vnode_t **vpp, char *od_name, 5345331Samw int flags, vnode_t *rootvp, cred_t *cr, caller_context_t *ct) 5355331Samw { 5365331Samw int error = 0; 5375331Samw int option_flags = 0; 5385331Samw pathname_t rpn; 5395331Samw 5405331Samw if (*name == '\0') 5415331Samw return (EINVAL); 5425331Samw 5435331Samw ASSERT(vpp); 5445331Samw *vpp = NULL; 5455331Samw 5465331Samw if ((name[0] == '.') && (name[1] == '.') && (name[2] == 0)) { 5475331Samw if (rootvp && (dvp == rootvp)) { 5485331Samw VN_HOLD(dvp); 5495331Samw *vpp = dvp; 5505331Samw return (0); 5515331Samw } 5525331Samw 5535331Samw if (dvp->v_flag & VROOT) { 5545331Samw vfs_t *vfsp; 5555331Samw vnode_t *cvp = dvp; 5565331Samw 5575331Samw /* 5585331Samw * Set dvp and check for races with forced unmount 5595331Samw * (see lookuppnvp()) 5605331Samw */ 5615331Samw 5625331Samw vfsp = cvp->v_vfsp; 5635331Samw vfs_rlock_wait(vfsp); 5645331Samw if (((dvp = cvp->v_vfsp->vfs_vnodecovered) == NULL) || 5655331Samw (cvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)) { 5665331Samw vfs_unlock(vfsp); 5675331Samw return (EIO); 5685331Samw } 5695331Samw vfs_unlock(vfsp); 5705331Samw } 5715331Samw } 5725331Samw 5735331Samw 5745331Samw 5755331Samw if (flags & SMB_IGNORE_CASE) 5765331Samw option_flags = FIGNORECASE; 5775331Samw 5785331Samw pn_alloc(&rpn); 5795331Samw 5805331Samw error = VOP_LOOKUP(dvp, name, vpp, NULL, option_flags, NULL, cr, 5815331Samw ct, NULL, &rpn); 5825331Samw 5835331Samw if ((error == 0) && od_name) { 5845331Samw bzero(od_name, MAXNAMELEN); 5855331Samw if (option_flags == FIGNORECASE) 5865331Samw (void) strlcpy(od_name, rpn.pn_buf, MAXNAMELEN); 5875331Samw else 5885331Samw (void) strlcpy(od_name, name, MAXNAMELEN); 5895331Samw } 5905331Samw 5915331Samw pn_free(&rpn); 5925331Samw return (error); 5935331Samw } 5945331Samw 5955331Samw int 5965331Samw smb_vop_create(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp, 5975331Samw int flags, cred_t *cr, caller_context_t *ct, vsecattr_t *vsap) 5985331Samw { 5995331Samw int error; 6005331Samw int option_flags = 0; 6015331Samw 6025331Samw if (flags & SMB_IGNORE_CASE) 6035331Samw option_flags = FIGNORECASE; 6045331Samw 6055331Samw smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask); 6065331Samw 6075331Samw error = VOP_CREATE(dvp, name, &attr->sa_vattr, EXCL, 6085331Samw attr->sa_vattr.va_mode, vpp, cr, option_flags, ct, vsap); 6095331Samw 6105331Samw return (error); 6115331Samw } 6125331Samw 6135331Samw int 6145331Samw smb_vop_remove(vnode_t *dvp, char *name, int flags, cred_t *cr, 6155331Samw caller_context_t *ct) 6165331Samw { 6175331Samw int error; 6185331Samw int option_flags = 0; 6195331Samw 6205331Samw if (flags & SMB_IGNORE_CASE) 6215331Samw option_flags = FIGNORECASE; 6225331Samw 6235331Samw error = VOP_REMOVE(dvp, name, cr, ct, option_flags); 6245331Samw 6255331Samw return (error); 6265331Samw } 6275331Samw 6285331Samw /* 6295331Samw * smb_vop_rename() 6305331Samw * 6315331Samw * The rename is for files in the same tree (identical TID) only. 6325331Samw */ 6335331Samw 6345331Samw int 6355331Samw smb_vop_rename(vnode_t *from_dvp, char *from_name, vnode_t *to_dvp, 6365331Samw char *to_name, int flags, cred_t *cr, caller_context_t *ct) 6375331Samw { 6385331Samw int error; 6395331Samw int option_flags = 0; 6405331Samw 6415331Samw 6425331Samw if (flags & SMB_IGNORE_CASE) 6435331Samw option_flags = FIGNORECASE; 6445331Samw 6455331Samw error = VOP_RENAME(from_dvp, from_name, to_dvp, to_name, cr, 6465331Samw ct, option_flags); 6475331Samw 6485331Samw return (error); 6495331Samw } 6505331Samw 6515331Samw int 6525331Samw smb_vop_mkdir(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp, 6535331Samw int flags, cred_t *cr, caller_context_t *ct, vsecattr_t *vsap) 6545331Samw { 6555331Samw int error; 6565331Samw int option_flags = 0; 6575331Samw 6585331Samw 6595331Samw 6605331Samw if (flags & SMB_IGNORE_CASE) 6615331Samw option_flags = FIGNORECASE; 6625331Samw 6635331Samw smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask); 6645331Samw 6655331Samw error = VOP_MKDIR(dvp, name, &attr->sa_vattr, vpp, cr, ct, 6665331Samw option_flags, vsap); 6675331Samw 6685331Samw return (error); 6695331Samw } 6705331Samw 6715331Samw /* 6725331Samw * smb_vop_rmdir() 6735331Samw * 6745331Samw * Only simple rmdir supported, consistent with NT semantics 6755331Samw * (can only remove an empty directory). 6765331Samw * 6775331Samw */ 6785331Samw 6795331Samw int 6805331Samw smb_vop_rmdir(vnode_t *dvp, char *name, int flags, cred_t *cr, 6815331Samw caller_context_t *ct) 6825331Samw { 6835331Samw int error; 6845331Samw int option_flags = 0; 6855331Samw 6865331Samw if (flags & SMB_IGNORE_CASE) 6875331Samw option_flags = FIGNORECASE; 6885331Samw 6895331Samw /* 6905331Samw * Comments adapted from rfs_rmdir(). 6915331Samw * 6925331Samw * VOP_RMDIR now takes a new third argument (the current 6935331Samw * directory of the process). That's because rmdir 6945331Samw * wants to return EINVAL if one tries to remove ".". 6955331Samw * Of course, SMB servers do not know what their 6965331Samw * clients' current directories are. We fake it by 6975331Samw * supplying a vnode known to exist and illegal to 6985331Samw * remove. 6995331Samw */ 7005331Samw 7015331Samw error = VOP_RMDIR(dvp, name, rootdir, cr, ct, option_flags); 7025331Samw return (error); 7035331Samw } 7045331Samw 7055331Samw int 7065331Samw smb_vop_commit(vnode_t *vp, cred_t *cr, caller_context_t *ct) 7075331Samw { 7085331Samw return (VOP_FSYNC(vp, 1, cr, ct)); 7095331Samw } 7105331Samw 7115331Samw /* 7125331Samw * smb_vop_readdir() 7135331Samw * 7145331Samw * Upon return, the "name" field will contain either the on-disk name or, if 7155331Samw * it needs mangling or has a case-insensitive collision, the mangled 7165331Samw * "shortname." 7175331Samw * 7185331Samw * vpp is an optional parameter. If non-NULL, it will contain a pointer to 7195331Samw * the vnode for the name that is looked up (the vnode will be returned held). 7205331Samw * 7215331Samw * od_name is an optional parameter (NULL can be passed if the on-disk name 7225331Samw * is not needed by the caller). 7235331Samw */ 7245331Samw 7255331Samw int 7265331Samw smb_vop_readdir(vnode_t *dvp, uint32_t *cookiep, char *name, int *namelen, 7275331Samw ino64_t *inop, vnode_t **vpp, char *od_name, int flags, cred_t *cr, 7285331Samw caller_context_t *ct) 7295331Samw { 7305331Samw int num_bytes; 7315331Samw int error = 0; 7325331Samw char *dirbuf = NULL; 7335331Samw 7345331Samw ASSERT(dvp); 7355331Samw ASSERT(cookiep); 7365331Samw ASSERT(name); 7375331Samw ASSERT(namelen); 7385331Samw ASSERT(inop); 7395331Samw ASSERT(cr); 7405331Samw ASSERT(ct); 7415331Samw 7425331Samw if (dvp->v_type != VDIR) { 7435331Samw *namelen = 0; 7445331Samw return (ENOTDIR); 7455331Samw } 7465331Samw 7475331Samw if (vpp) 7485331Samw *vpp = NULL; 7495331Samw 7505331Samw dirbuf = kmem_zalloc(SMB_MINLEN_RDDIR_BUF, KM_SLEEP); 7515331Samw num_bytes = SMB_MINLEN_RDDIR_BUF; 7525331Samw 7535331Samw /* 7545331Samw * The goal is to retrieve the first valid entry from *cookiep 7555331Samw * forward. smb_vop_readdir_readpage() collects an 7565331Samw * SMB_MINLEN_RDDIR_BUF-size "page" of directory entry information. 7575331Samw * smb_vop_readdir_entry() attempts to find the first valid entry 7585331Samw * in that page. 7595331Samw */ 7605331Samw 7615331Samw while ((error = smb_vop_readdir_readpage(dvp, dirbuf, *cookiep, 7625331Samw &num_bytes, cr, ct, flags)) == 0) { 7635331Samw 7645331Samw if (num_bytes <= 0) 7655331Samw break; 7665331Samw 7675331Samw name[0] = '\0'; 7685331Samw 7695331Samw error = smb_vop_readdir_entry(dvp, cookiep, name, namelen, 7705331Samw inop, vpp, od_name, flags, cr, ct, dirbuf, 7715331Samw num_bytes); 7725331Samw 7735331Samw if (error) 7745331Samw break; 7755331Samw 7765331Samw if (*name) 7775331Samw break; 7785331Samw 7795331Samw bzero(dirbuf, SMB_MINLEN_RDDIR_BUF); 7805331Samw num_bytes = SMB_MINLEN_RDDIR_BUF; 7815331Samw } 7825331Samw 7835331Samw 7845331Samw if (error) { 7855331Samw kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 7865331Samw *namelen = 0; 7875331Samw return (error); 7885331Samw } 7895331Samw 7905331Samw if (num_bytes == 0) { /* EOF */ 7915331Samw kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 7925331Samw *cookiep = SMB_EOF; 7935331Samw *namelen = 0; 7945331Samw return (0); 7955331Samw } 7965331Samw 7975331Samw kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 7985331Samw return (0); 7995331Samw } 8005331Samw 8015331Samw /* 8025331Samw * smb_vop_readdir_readpage() 8035331Samw * 8045331Samw * Collects an SMB_MINLEN_RDDIR_BUF "page" of directory entries. (The 8055331Samw * directory entries are returned in an fs-independent format by the 8065331Samw * underlying file system. That is, the "page" of information returned is 8075331Samw * not literally stored on-disk in the format returned.) 8085331Samw * 8095331Samw * Much of the following is borrowed from getdents64() 8105331Samw * 8115331Samw * MAXGETDENTS_SIZE is defined in getdents.c 8125331Samw */ 8135331Samw 8145331Samw #define MAXGETDENTS_SIZE (64 * 1024) 8155331Samw 8165331Samw static int 8175331Samw smb_vop_readdir_readpage(vnode_t *vp, void *buf, uint32_t offset, int *count, 8185331Samw cred_t *cr, caller_context_t *ct, int flags) 8195331Samw { 8205331Samw int error = 0; 8215331Samw int rdirent_flags = 0; 8225331Samw int sink; 8235331Samw struct uio auio; 8245331Samw struct iovec aiov; 8255331Samw 8265331Samw if (vp->v_type != VDIR) 8275331Samw return (ENOTDIR); 8285331Samw 8295331Samw /* entflags not working for streams so don't try to use them */ 8305331Samw if (!(flags & SMB_STREAM_RDDIR) && 8315331Samw (vfs_has_feature(vp->v_vfsp, VFSFT_DIRENTFLAGS))) { 8325331Samw /* 8335331Samw * Setting V_RDDIR_ENTFLAGS will cause the buffer to 8345331Samw * be filled with edirent_t structures (instead of 8355331Samw * dirent64_t structures). 8365331Samw */ 8375331Samw rdirent_flags = V_RDDIR_ENTFLAGS; 8385331Samw 8395331Samw if (*count < sizeof (edirent_t)) 8405331Samw return (EINVAL); 8415331Samw } else { 8425331Samw if (*count < sizeof (dirent64_t)) 8435331Samw return (EINVAL); 8445331Samw } 8455331Samw 8465331Samw if (*count > MAXGETDENTS_SIZE) 8475331Samw *count = MAXGETDENTS_SIZE; 8485331Samw 8495331Samw aiov.iov_base = buf; 8505331Samw aiov.iov_len = *count; 8515331Samw auio.uio_iov = &aiov; 8525331Samw auio.uio_iovcnt = 1; 8535331Samw auio.uio_loffset = (uint64_t)offset; 8545331Samw auio.uio_segflg = UIO_SYSSPACE; 8555331Samw auio.uio_resid = *count; 8565331Samw auio.uio_fmode = 0; 8575331Samw 8585331Samw (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL); 8595331Samw error = VOP_READDIR(vp, &auio, cr, &sink, ct, rdirent_flags); 8605331Samw VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 8615331Samw 8625331Samw if (error) { 8635331Samw if (error == ENOENT) { 8645331Samw /* Fake EOF if offset is bad due to dropping of lock */ 8655331Samw *count = 0; 8665331Samw return (0); 8675331Samw } else { 8685331Samw return (error); 8695331Samw } 8705331Samw } 8715331Samw 8725331Samw /* 8735331Samw * Windows cannot handle an offset > SMB_EOF. 8745331Samw * Pretend we are at EOF. 8755331Samw */ 8765331Samw 8775331Samw if (auio.uio_loffset > SMB_EOF) { 8785331Samw *count = 0; 8795331Samw return (0); 8805331Samw } 8815331Samw 8825331Samw *count = *count - auio.uio_resid; 8835331Samw return (0); 8845331Samw } 8855331Samw 8865331Samw /* 8875331Samw * smb_vop_readdir_entry() 8885331Samw * 8895331Samw * This function retrieves the first valid entry from the 8905331Samw * SMB_MINLEN_RDDIR_BUF-sized buffer returned by smb_vop_readdir_readpage() 8915331Samw * to smb_vop_readdir(). 8925331Samw * 8935331Samw * Both dirent64_t and edirent_t structures need to be handled. The former is 8945331Samw * needed for file systems that do not support VFSFT_DIRENTFLAGS. The latter 8955331Samw * is required for proper handling of case collisions on file systems that 8965331Samw * support case-insensitivity. edirent_t structures are also used for 8975331Samw * case-sensitive file systems if VFSFT_DIRENTFLAGS is supported. 8985331Samw */ 8995331Samw 9005331Samw static int 9015331Samw smb_vop_readdir_entry(vnode_t *dvp, uint32_t *cookiep, char *name, int *namelen, 9025331Samw ino64_t *inop, vnode_t **vpp, char *od_name, int flags, cred_t *cr, 9035331Samw caller_context_t *ct, char *dirbuf, int num_bytes) 9045331Samw { 9055331Samw uint32_t next_cookie; 9065331Samw int ebufsize; 9075331Samw int error = 0; 9085331Samw int len; 9095331Samw int rc; 9105331Samw char shortname[MANGLE_NAMELEN]; 9115331Samw char name83[MANGLE_NAMELEN]; 9125331Samw char *ebuf = NULL; 9135331Samw edirent_t *edp; 9145331Samw dirent64_t *dp = NULL; 9155331Samw vnode_t *vp = NULL; 9165331Samw 9175331Samw ASSERT(dirbuf); 9185331Samw 9195331Samw /* 9205331Samw * Use edirent_t structure for both 9215331Samw * entflags not working for streams so don't try to use them 9225331Samw */ 9235331Samw if (!(flags & SMB_STREAM_RDDIR) && 9245331Samw (vfs_has_feature(dvp->v_vfsp, VFSFT_DIRENTFLAGS))) { 9255331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 9265331Samw edp = (edirent_t *)dirbuf; 9275331Samw } else { 9285331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 9295331Samw dp = (dirent64_t *)dirbuf; 9305331Samw ebufsize = EDIRENT_RECLEN(MAXNAMELEN); 9315331Samw ebuf = kmem_zalloc(ebufsize, KM_SLEEP); 9325331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 9335331Samw edp = (edirent_t *)ebuf; 9345331Samw } 9355331Samw 9365331Samw while (edp) { 9375331Samw if (dp) 9385331Samw DP_TO_EDP(dp, edp); 9395331Samw 9405331Samw next_cookie = (uint32_t)edp->ed_off; 9415331Samw if (edp->ed_ino == 0) { 9425331Samw *cookiep = next_cookie; 9435331Samw 9445331Samw if (dp) { 9455331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 9465331Samw DP_ADVANCE(dp, dirbuf, num_bytes); 9475331Samw if (dp == NULL) 9485331Samw edp = NULL; 9495331Samw } else { 9505331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 9515331Samw EDP_ADVANCE(edp, dirbuf, num_bytes); 9525331Samw } 9535331Samw continue; 9545331Samw } 9555331Samw 9565331Samw len = strlen(edp->ed_name); 9575331Samw 9585331Samw if (*namelen < len) { 9595331Samw *namelen = 0; 9605331Samw 9615331Samw if (ebuf) 9625331Samw kmem_free(ebuf, ebufsize); 9635331Samw 9645331Samw return (EOVERFLOW); 9655331Samw } 9665331Samw 9675331Samw /* 9685331Samw * Do not pass SMB_IGNORE_CASE to smb_vop_lookup 9695331Samw */ 9705331Samw 9715331Samw error = smb_vop_lookup(dvp, edp->ed_name, vpp ? vpp : &vp, 9725331Samw od_name, 0, NULL, cr, ct); 9735331Samw 9745331Samw if (error) { 9755331Samw if (error == ENOENT) { 9765331Samw *cookiep = (uint32_t)next_cookie; 9775331Samw 9785331Samw if (dp) { 9795331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 9805331Samw DP_ADVANCE(dp, dirbuf, num_bytes); 9815331Samw if (dp == NULL) 9825331Samw edp = NULL; 9835331Samw } else { 9845331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 9855331Samw EDP_ADVANCE(edp, dirbuf, num_bytes); 9865331Samw } 9875331Samw continue; 9885331Samw } 9895331Samw 9905331Samw 9915331Samw *namelen = 0; 9925331Samw 9935331Samw if (ebuf) 9945331Samw kmem_free(ebuf, ebufsize); 9955331Samw 9965331Samw return (error); 9975331Samw } 9985331Samw 9995331Samw if ((flags & SMB_IGNORE_CASE) && ED_CASE_CONFLICTS(edp)) { 10005331Samw rc = smb_mangle_name(edp->ed_ino, edp->ed_name, 10015331Samw shortname, name83, 1); 10025331Samw 10035331Samw if (rc == 1) { /* success */ 10045331Samw (void) strlcpy(name, shortname, *namelen + 1); 10055331Samw *namelen = strlen(shortname); 10065331Samw } else { 10075331Samw (void) strlcpy(name, edp->ed_name, 10085331Samw *namelen + 1); 10095331Samw name[*namelen] = '\0'; 10105331Samw } 10115331Samw 10125331Samw } else { 10135331Samw (void) strlcpy(name, edp->ed_name, *namelen + 1); 10145331Samw *namelen = len; 10155331Samw } 10165331Samw 10175331Samw if (vpp == NULL) 10185331Samw VN_RELE(vp); 10195331Samw 10205331Samw if (inop) 10215331Samw *inop = edp->ed_ino; 10225331Samw 10235331Samw *cookiep = (uint32_t)next_cookie; 10245331Samw break; 10255331Samw } 10265331Samw 10275331Samw if (ebuf) 10285331Samw kmem_free(ebuf, ebufsize); 10295331Samw 10305331Samw return (error); 10315331Samw } 10325331Samw 10335331Samw /* 10345331Samw * smb_sa_to_va_mask 10355331Samw * 10365331Samw * Set va_mask by running through the SMB_AT_* #define's and 10375331Samw * setting those bits that correspond to the SMB_AT_* bits 10385331Samw * set in sa_mask. 10395331Samw */ 10405331Samw 10415331Samw void 10425331Samw smb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp) 10435331Samw { 10445331Samw int i; 10455331Samw uint_t smask; 10465331Samw 10475331Samw smask = (sa_mask); 10485331Samw for (i = SMB_AT_TYPE; (i < SMB_AT_MAX) && (smask != 0); ++i) { 10495331Samw if (smask & 1) 10505331Samw *(va_maskp) |= smb_attrmap[i]; 10515331Samw 10525331Samw smask >>= 1; 10535331Samw } 10545331Samw } 10555331Samw 10565331Samw /* 10575331Samw * smb_vop_getdents() 10585331Samw * 10595331Samw * Upon success, the smb_node corresponding to each entry returned will 10605331Samw * have a reference taken on it. These will be released in 10615331Samw * smb_trans2_find_get_dents(). 10625331Samw * 10635331Samw * If an error is returned from this routine, a list of already processed 10645331Samw * entries will be returned. The smb_nodes corresponding to these entries 10655331Samw * will be referenced, and will be released in smb_trans2_find_get_dents(). 10665331Samw * 10675331Samw * The returned dp->d_name field will contain either the on-disk name or, if 10685331Samw * it needs mangling or has a case-insensitive collision, the mangled 10695331Samw * "shortname." In this case, the on-disk name can be retrieved from the 10705331Samw * smb_node's od_name (the smb_node is passed to smb_gather_dents_info()). 10715331Samw */ 10725331Samw 10735331Samw int /*ARGSUSED*/ 10745331Samw smb_vop_getdents( 10755331Samw smb_node_t *dir_snode, 10765331Samw uint32_t *cookiep, 10775331Samw uint64_t *verifierp, 10785331Samw int32_t *dircountp, 10795331Samw char *arg, 10805331Samw char *pattern, 10815331Samw uint32_t flags, 10825331Samw smb_request_t *sr, 10835331Samw cred_t *cr, 10845331Samw caller_context_t *ct) 10855331Samw { 10865331Samw int error = 0; 10875331Samw int maxentries; 10885331Samw int num_bytes; 10895331Samw int resid; 10905331Samw char *dirbuf = NULL; 10915331Samw vnode_t *dvp; 10925331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 10935331Samw smb_dent_info_hdr_t *ihdr = (smb_dent_info_hdr_t *)arg; 10945331Samw 10955331Samw dvp = dir_snode->vp; 10965331Samw 10975331Samw resid = ihdr->uio.uio_resid; 10985331Samw maxentries = resid / SMB_MAX_DENT_INFO_SIZE; 10995331Samw 11005331Samw bzero(ihdr->iov->iov_base, resid); 11015331Samw 11025331Samw dirbuf = kmem_alloc(SMB_MINLEN_RDDIR_BUF, KM_SLEEP); 11035331Samw 11045331Samw while (maxentries) { 11055331Samw 11065331Samw bzero(dirbuf, SMB_MINLEN_RDDIR_BUF); 11075331Samw 11085331Samw num_bytes = SMB_MINLEN_RDDIR_BUF; 11095331Samw error = smb_vop_readdir_readpage(dvp, dirbuf, *cookiep, 11105331Samw &num_bytes, cr, ct, flags); 11115331Samw 11125331Samw if (error || (num_bytes <= 0)) 11135331Samw break; 11145331Samw 11155331Samw error = smb_vop_getdents_entries(dir_snode, cookiep, dircountp, 11165331Samw arg, flags, sr, cr, ct, dirbuf, &maxentries, num_bytes, 11175331Samw pattern); 11185331Samw 11195331Samw if (error) 11205331Samw goto out; 11215331Samw } 11225331Samw 11235331Samw if (num_bytes < 0) { 11245331Samw error = -1; 11255331Samw } else if (num_bytes == 0) { 11265331Samw *cookiep = SMB_EOF; 11275331Samw error = 0; 11285331Samw } else { 11295331Samw error = 0; 11305331Samw } 11315331Samw 11325331Samw out: 11335331Samw if (dirbuf) 11345331Samw kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 11355331Samw 11365331Samw return (error); 11375331Samw } 11385331Samw 11395331Samw /* 11405331Samw * smb_vop_getdents_entries() 11415331Samw * 11425331Samw * This function retrieves names from the SMB_MINLEN_RDDIR_BUF-sized buffer 11435331Samw * returned by smb_vop_readdir_readpage() to smb_vop_getdents(). 11445331Samw * 11455331Samw * Both dirent64_t and edirent_t structures need to be handled. The former is 11465331Samw * needed for file systems that do not support VFSFT_DIRENTFLAGS. The latter 11475331Samw * is required for properly handling case collisions on file systems that 11485331Samw * support case-insensitivity. edirent_t is also used on case-sensitive 11495331Samw * file systems where VFSFT_DIRENTFLAGS is available. 11505331Samw */ 11515331Samw 11525331Samw static int 11535331Samw smb_vop_getdents_entries( 11545331Samw smb_node_t *dir_snode, 11555331Samw uint32_t *cookiep, 11565331Samw int32_t *dircountp, 11575331Samw char *arg, 11585331Samw uint32_t flags, 11595331Samw struct smb_request *sr, 11605331Samw cred_t *cr, 11615331Samw caller_context_t *ct, 11625331Samw char *dirbuf, 11635331Samw int *maxentries, 11645331Samw int num_bytes, 11655331Samw char *pattern) 11665331Samw { 11675331Samw uint32_t next_cookie; 11685331Samw int ebufsize; 11695331Samw char *tmp_name; 11705331Samw int error; 11715331Samw int rc; 11725331Samw char shortname[MANGLE_NAMELEN]; 11735331Samw char name83[MANGLE_NAMELEN]; 11745331Samw char *ebuf = NULL; 11755331Samw dirent64_t *dp = NULL; 11765331Samw edirent_t *edp; 11775331Samw smb_node_t *ret_snode; 11785331Samw smb_attr_t ret_attr; 11795331Samw vnode_t *dvp; 11805331Samw vnode_t *fvp; 11815331Samw 11825331Samw ASSERT(dirbuf); 11835331Samw 11845331Samw dvp = dir_snode->vp; 11855331Samw 11865331Samw if (vfs_has_feature(dvp->v_vfsp, VFSFT_DIRENTFLAGS)) { 11875331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 11885331Samw edp = (edirent_t *)dirbuf; 11895331Samw } else { 11905331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 11915331Samw dp = (dirent64_t *)dirbuf; 11925331Samw ebufsize = EDIRENT_RECLEN(MAXNAMELEN); 11935331Samw ebuf = kmem_zalloc(ebufsize, KM_SLEEP); 11945331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 11955331Samw edp = (edirent_t *)ebuf; 11965331Samw } 11975331Samw 11985331Samw while (edp) { 11995331Samw if (dp) 12005331Samw DP_TO_EDP(dp, edp); 12015331Samw 12025331Samw if (*maxentries == 0) 12035331Samw break; 12045331Samw 12055331Samw next_cookie = (uint32_t)edp->ed_off; 12065331Samw 12075331Samw if (edp->ed_ino == 0) { 12085331Samw *cookiep = next_cookie; 12095331Samw if (dp) { 12105331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 12115331Samw DP_ADVANCE(dp, dirbuf, num_bytes); 12125331Samw if (dp == NULL) 12135331Samw edp = NULL; 12145331Samw } else { 12155331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 12165331Samw EDP_ADVANCE(edp, dirbuf, num_bytes); 12175331Samw } 12185331Samw continue; 12195331Samw } 12205331Samw 12215331Samw error = smb_vop_lookup(dvp, edp->ed_name, &fvp, 12225331Samw NULL, 0, NULL, cr, ct); 12235331Samw 12245331Samw if (error) { 12255331Samw if (error == ENOENT) { 12265331Samw *cookiep = next_cookie; 12275331Samw if (dp) { 12285331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 12295331Samw DP_ADVANCE(dp, dirbuf, 12305331Samw num_bytes); 12315331Samw if (dp == NULL) 12325331Samw edp = NULL; 12335331Samw } else { 12345331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 12355331Samw EDP_ADVANCE(edp, dirbuf, 12365331Samw num_bytes); 12375331Samw } 12385331Samw continue; 12395331Samw } 12405331Samw if (ebuf) 12415331Samw kmem_free(ebuf, ebufsize); 12425331Samw 12435331Samw return (error); 12445331Samw } 12455331Samw 12465331Samw ret_snode = smb_node_lookup(sr, NULL, cr, fvp, 12475331Samw edp->ed_name, dir_snode, NULL, &ret_attr); 12485331Samw 12495331Samw if (ret_snode == NULL) { 12505331Samw VN_RELE(fvp); 12515331Samw 12525331Samw if (ebuf) 12535331Samw kmem_free(ebuf, ebufsize); 12545331Samw 12555331Samw return (ENOMEM); 12565331Samw } 12575331Samw 12585331Samw if (smb_match_name(edp->ed_ino, edp->ed_name, shortname, 12595331Samw name83, pattern, (flags & SMB_IGNORE_CASE))) { 12605331Samw 12615331Samw tmp_name = edp->ed_name; 12625331Samw 12635331Samw if ((flags & SMB_IGNORE_CASE) && 12645331Samw ED_CASE_CONFLICTS(edp)) { 12655331Samw rc = smb_mangle_name(edp->ed_ino, edp->ed_name, 12665331Samw shortname, name83, 1); 12675331Samw if (rc == 1) 12685331Samw tmp_name = shortname; 12695331Samw } else { 12705331Samw rc = smb_mangle_name(edp->ed_ino, edp->ed_name, 12715331Samw shortname, name83, 0); 12725331Samw } 12735331Samw 12745331Samw if (rc != 1) { 12755331Samw (void) strlcpy(shortname, edp->ed_name, 12765331Samw MANGLE_NAMELEN); 12775331Samw (void) strlcpy(name83, edp->ed_name, 12785331Samw MANGLE_NAMELEN); 12795331Samw shortname[MANGLE_NAMELEN - 1] = '\0'; 12805331Samw name83[MANGLE_NAMELEN - 1] = '\0'; 12815331Samw } 12825331Samw 12835331Samw error = smb_gather_dents_info(arg, edp->ed_ino, 12845331Samw strlen(tmp_name), tmp_name, next_cookie, dircountp, 12855331Samw &ret_attr, ret_snode, shortname, name83); 12865331Samw 12875331Samw if (error > 0) { 12885331Samw if (ebuf) 12895331Samw kmem_free(ebuf, ebufsize); 12905331Samw return (error); 12915331Samw } 12925331Samw 12935331Samw /* 12945331Samw * Treat errors from smb_gather_dents_info() that are 12955331Samw * < 0 the same as EOF. 12965331Samw */ 12975331Samw if (error < 0) { 12985331Samw if (ebuf) 12995331Samw kmem_free(ebuf, ebufsize); 13005331Samw *maxentries = 0; 13015331Samw return (0); 13025331Samw } 13035331Samw (*maxentries)--; 13045331Samw } else { 13055331Samw smb_node_release(ret_snode); 13065331Samw } 13075331Samw 13085331Samw *cookiep = next_cookie; 13095331Samw 13105331Samw if (dp) { 13115331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 13125331Samw DP_ADVANCE(dp, dirbuf, num_bytes); 13135331Samw if (dp == NULL) 13145331Samw edp = NULL; 13155331Samw } else { 13165331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 13175331Samw EDP_ADVANCE(edp, dirbuf, num_bytes); 13185331Samw } 13195331Samw } 13205331Samw 13215331Samw if (ebuf) 13225331Samw kmem_free(ebuf, ebufsize); 13235331Samw 13245331Samw return (0); 13255331Samw } 13265331Samw 13275331Samw /* 13285331Samw * smb_vop_stream_lookup() 13295331Samw * 13305331Samw * The name returned in od_name is the on-disk name of the stream with the 13315331Samw * SMB_STREAM_PREFIX stripped off. od_name should be allocated to MAXNAMELEN 13325331Samw * by the caller. 13335331Samw */ 13345331Samw 13355331Samw int 13365331Samw smb_vop_stream_lookup(vnode_t *fvp, char *stream_name, vnode_t **vpp, 13375331Samw char *od_name, vnode_t **xattrdirvpp, int flags, vnode_t *rootvp, 13385331Samw cred_t *cr, caller_context_t *ct) 13395331Samw { 13405331Samw char *solaris_stream_name; 13415331Samw char *name; 13425331Samw int error; 13435331Samw 13445331Samw if ((error = smb_vop_lookup_xattrdir(fvp, xattrdirvpp, 13455331Samw LOOKUP_XATTR | CREATE_XATTR_DIR, cr, ct)) != 0) 13465331Samw return (error); 13475331Samw 13485331Samw /* 13495331Samw * Prepend SMB_STREAM_PREFIX to stream name 13505331Samw */ 13515331Samw 13525331Samw solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 13535331Samw (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX, 13545331Samw stream_name); 13555331Samw 13565331Samw /* 13575331Samw * "name" will hold the on-disk name returned from smb_vop_lookup 13585331Samw * for the stream, including the SMB_STREAM_PREFIX. 13595331Samw */ 13605331Samw 13615331Samw name = kmem_zalloc(MAXNAMELEN, KM_SLEEP); 13625331Samw 13635331Samw if ((error = smb_vop_lookup(*xattrdirvpp, solaris_stream_name, vpp, 13645331Samw name, flags, rootvp, cr, ct)) != 0) { 13655331Samw VN_RELE(*xattrdirvpp); 13665331Samw } else { 13675331Samw (void) strlcpy(od_name, &(name[SMB_STREAM_PREFIX_LEN]), 13685331Samw MAXNAMELEN); 13695331Samw } 13705331Samw 13715331Samw kmem_free(solaris_stream_name, MAXNAMELEN); 13725331Samw kmem_free(name, MAXNAMELEN); 13735331Samw 13745331Samw return (error); 13755331Samw } 13765331Samw 13775331Samw int 13785331Samw smb_vop_stream_create(vnode_t *fvp, char *stream_name, smb_attr_t *attr, 13795331Samw vnode_t **vpp, vnode_t **xattrdirvpp, int flags, cred_t *cr, 13805331Samw caller_context_t *ct) 13815331Samw { 13825331Samw char *solaris_stream_name; 13835331Samw int error; 13845331Samw 13855331Samw if ((error = smb_vop_lookup_xattrdir(fvp, xattrdirvpp, 13865331Samw LOOKUP_XATTR | CREATE_XATTR_DIR, cr, ct)) != 0) 13875331Samw return (error); 13885331Samw 13895331Samw /* 13905331Samw * Prepend SMB_STREAM_PREFIX to stream name 13915331Samw */ 13925331Samw 13935331Samw solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 13945331Samw (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX, 13955331Samw stream_name); 13965331Samw 13975331Samw if ((error = smb_vop_create(*xattrdirvpp, solaris_stream_name, attr, 13985331Samw vpp, flags, cr, ct, NULL)) != 0) 13995331Samw VN_RELE(*xattrdirvpp); 14005331Samw 14015331Samw kmem_free(solaris_stream_name, MAXNAMELEN); 14025331Samw 14035331Samw return (error); 14045331Samw } 14055331Samw 14065331Samw int 14075331Samw smb_vop_stream_remove(vnode_t *vp, char *stream_name, int flags, cred_t *cr, 14085331Samw caller_context_t *ct) 14095331Samw { 14105331Samw char *solaris_stream_name; 14115331Samw vnode_t *xattrdirvp; 14125331Samw int error; 14135331Samw 14145331Samw if ((error = smb_vop_lookup_xattrdir(vp, &xattrdirvp, LOOKUP_XATTR, cr, 14155331Samw ct)) != 0) 14165331Samw return (error); 14175331Samw 14185331Samw /* 14195331Samw * Prepend SMB_STREAM_PREFIX to stream name 14205331Samw */ 14215331Samw 14225331Samw solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 14235331Samw (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX, 14245331Samw stream_name); 14255331Samw 14265331Samw /* XXX might have to use kcred */ 14275331Samw error = smb_vop_remove(xattrdirvp, solaris_stream_name, flags, cr, ct); 14285331Samw 14295331Samw kmem_free(solaris_stream_name, MAXNAMELEN); 14305331Samw 14315331Samw return (error); 14325331Samw } 14335331Samw 14345331Samw /* 14355331Samw * smb_vop_stream_readdir() 14365331Samw * 14375331Samw * Note: stream_info.size is not filled in in this routine. 14385331Samw * It needs to be filled in by the caller due to the parameters for getattr. 14395331Samw * 14405331Samw * stream_info.name is set to the on-disk stream name with the SMB_STREAM_PREFIX 14415331Samw * removed. 14425331Samw */ 14435331Samw 14445331Samw int 14455331Samw smb_vop_stream_readdir(vnode_t *fvp, uint32_t *cookiep, 14465331Samw struct fs_stream_info *stream_info, vnode_t **vpp, vnode_t **xattrdirvpp, 14475331Samw int flags, cred_t *cr, caller_context_t *ct) 14485331Samw { 14495331Samw int nsize = MAXNAMELEN-1; 14505331Samw int error = 0; 14515331Samw ino64_t ino; 14525331Samw char *tmp_name; 14535331Samw vnode_t *xattrdirvp; 14545331Samw vnode_t *vp; 14555331Samw 14565331Samw if ((error = smb_vop_lookup_xattrdir(fvp, &xattrdirvp, LOOKUP_XATTR, 14575331Samw cr, ct)) != 0) 14585331Samw return (error); 14595331Samw 14605331Samw bzero(stream_info->name, sizeof (stream_info->name)); 14615331Samw stream_info->size = 0; 14625331Samw 14635331Samw tmp_name = kmem_zalloc(MAXNAMELEN, KM_SLEEP); 14645331Samw 14655331Samw for (;;) { 14665331Samw error = smb_vop_readdir(xattrdirvp, cookiep, tmp_name, &nsize, 14675331Samw &ino, &vp, NULL, flags | SMB_STREAM_RDDIR, cr, ct); 14685331Samw 14695331Samw if (error || (*cookiep == SMB_EOF)) 14705331Samw break; 14715331Samw 14725331Samw if (strncmp(tmp_name, SMB_STREAM_PREFIX, 14735331Samw SMB_STREAM_PREFIX_LEN)) { 14745331Samw VN_RELE(vp); 14755331Samw continue; 14765331Samw } 14775331Samw 14785331Samw tmp_name[nsize] = '\0'; 14795331Samw (void) strlcpy(stream_info->name, 14805331Samw &(tmp_name[SMB_STREAM_PREFIX_LEN]), 14815331Samw sizeof (stream_info->name)); 14825331Samw 14835331Samw nsize -= SMB_STREAM_PREFIX_LEN; 14845331Samw break; 14855331Samw } 14865331Samw 14875331Samw if ((error == 0) && nsize) { 14885331Samw if (vpp) 14895331Samw *vpp = vp; 14905331Samw else 14915331Samw VN_RELE(vp); 14925331Samw 14935331Samw if (xattrdirvpp) 14945331Samw *xattrdirvpp = xattrdirvp; 14955331Samw else 14965331Samw VN_RELE(xattrdirvp); 14975331Samw 14985331Samw } 14995331Samw 15005331Samw kmem_free(tmp_name, MAXNAMELEN); 15015331Samw 15025331Samw return (error); 15035331Samw } 15045331Samw 15055331Samw int 15065331Samw smb_vop_lookup_xattrdir(vnode_t *fvp, vnode_t **xattrdirvpp, int flags, 15075331Samw cred_t *cr, caller_context_t *ct) 15085331Samw { 15095331Samw int error; 15105331Samw 15115331Samw error = VOP_LOOKUP(fvp, "", xattrdirvpp, NULL, flags, NULL, cr, ct, 15125331Samw NULL, NULL); 15135331Samw return (error); 15145331Samw } 15155331Samw 15165331Samw /* 15175331Samw * smb_vop_traverse_check() 15185331Samw * 15195331Samw * This function checks to see if the passed-in vnode has a file system 15205331Samw * mounted on it. If it does, the mount point is "traversed" and the 15215331Samw * vnode for the root of the file system is returned. 15225331Samw */ 15235331Samw 15245331Samw int 15255331Samw smb_vop_traverse_check(vnode_t **vpp) 15265331Samw { 15275331Samw int error; 15285331Samw 15295331Samw if (vn_mountedvfs(*vpp) == 0) 15305331Samw return (0); 15315331Samw 15325331Samw /* 15335331Samw * traverse() may return a different held vnode, even in the error case. 15345331Samw * If it returns a different vnode, it will have released the original. 15355331Samw */ 15365331Samw 15375331Samw error = traverse(vpp); 15385331Samw 15395331Samw return (error); 15405331Samw } 15415331Samw 15425331Samw int /*ARGSUSED*/ 15435331Samw smb_vop_statfs(vnode_t *vp, struct statvfs64 *statp, cred_t *cr) 15445331Samw { 15455331Samw int error; 15465331Samw 15475331Samw error = VFS_STATVFS(vp->v_vfsp, statp); 15485331Samw 15495331Samw return (error); 15505331Samw } 15515331Samw 15525331Samw /* 15535331Samw * smb_vop_acl_read 15545331Samw * 15555331Samw * Reads the ACL of the specified file into 'aclp'. 15565331Samw * acl_type is the type of ACL which the filesystem supports. 15575331Samw * 15585331Samw * Caller has to free the allocated memory for aclp by calling 15595331Samw * acl_free(). 15605331Samw */ 15615331Samw int 15625331Samw smb_vop_acl_read(vnode_t *vp, acl_t **aclp, int flags, acl_type_t acl_type, 15635331Samw cred_t *cr, caller_context_t *ct) 15645331Samw { 15655331Samw int error; 15665331Samw vsecattr_t vsecattr; 15675331Samw 15685331Samw ASSERT(vp); 15695331Samw ASSERT(aclp); 15705331Samw 15715331Samw *aclp = NULL; 15725331Samw bzero(&vsecattr, sizeof (vsecattr_t)); 15735331Samw 15745331Samw switch (acl_type) { 15755331Samw case ACLENT_T: 15765331Samw vsecattr.vsa_mask = VSA_ACL | VSA_ACLCNT | VSA_DFACL | 15775331Samw VSA_DFACLCNT; 15785331Samw break; 15795331Samw 15805331Samw case ACE_T: 15815331Samw vsecattr.vsa_mask = VSA_ACE | VSA_ACECNT | VSA_ACE_ACLFLAGS; 15825331Samw break; 15835331Samw 15845331Samw default: 15855331Samw return (EINVAL); 15865331Samw } 15875331Samw 15885331Samw if (error = VOP_GETSECATTR(vp, &vsecattr, flags, cr, ct)) 15895331Samw return (error); 15905331Samw 1591*5521Sas200622 *aclp = smb_fsacl_from_vsa(&vsecattr, acl_type); 15925331Samw if (vp->v_type == VDIR) 15935331Samw (*aclp)->acl_flags |= ACL_IS_DIR; 15945331Samw 15955331Samw return (0); 15965331Samw } 15975331Samw 15985331Samw /* 15995331Samw * smb_vop_acl_write 16005331Samw * 16015331Samw * Writes the given ACL in aclp for the specified file. 16025331Samw */ 16035331Samw int 16045331Samw smb_vop_acl_write(vnode_t *vp, acl_t *aclp, int flags, cred_t *cr, 16055331Samw caller_context_t *ct) 16065331Samw { 16075331Samw int error; 16085331Samw vsecattr_t vsecattr; 16095331Samw int aclbsize; 16105331Samw 16115331Samw ASSERT(vp); 16125331Samw ASSERT(aclp); 16135331Samw 1614*5521Sas200622 error = smb_fsacl_to_vsa(aclp, &vsecattr, &aclbsize); 16155331Samw 16165331Samw if (error == 0) { 16175331Samw (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); 16185331Samw error = VOP_SETSECATTR(vp, &vsecattr, flags, cr, ct); 16195331Samw VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 16205331Samw } 16215331Samw 16225331Samw if (aclbsize && vsecattr.vsa_aclentp) 16235331Samw kmem_free(vsecattr.vsa_aclentp, aclbsize); 16245331Samw 16255331Samw return (error); 16265331Samw } 16275331Samw 16285331Samw /* 16295331Samw * smb_vop_acl_type 16305331Samw * 16315331Samw * Determines the ACL type for the given vnode. 16325331Samw * ACLENT_T is a Posix ACL and ACE_T is a ZFS ACL. 16335331Samw */ 16345331Samw acl_type_t 16355331Samw smb_vop_acl_type(vnode_t *vp) 16365331Samw { 16375331Samw int error; 16385331Samw ulong_t whichacl; 16395331Samw 16405331Samw error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &whichacl, kcred, NULL); 16415331Samw if (error != 0) { 16425331Samw /* 16435331Samw * If we got an error, then the filesystem 16445331Samw * likely does not understand the _PC_ACL_ENABLED 16455331Samw * pathconf. In this case, we fall back to trying 16465331Samw * POSIX-draft (aka UFS-style) ACLs. 16475331Samw */ 16485331Samw whichacl = _ACL_ACLENT_ENABLED; 16495331Samw } 16505331Samw 16515331Samw if (!(whichacl & (_ACL_ACE_ENABLED | _ACL_ACLENT_ENABLED))) { 16525331Samw /* 16535331Samw * If the file system supports neither ACE nor 16545331Samw * ACLENT ACLs we will fall back to UFS-style ACLs 16555331Samw * like we did above if there was an error upon 16565331Samw * calling VOP_PATHCONF. 16575331Samw * 16585331Samw * ACE and ACLENT type ACLs are the only interfaces 16595331Samw * supported thus far. If any other bits are set on 16605331Samw * 'whichacl' upon return from VOP_PATHCONF, we will 16615331Samw * ignore them. 16625331Samw */ 16635331Samw whichacl = _ACL_ACLENT_ENABLED; 16645331Samw } 16655331Samw 16665331Samw if (whichacl == _ACL_ACLENT_ENABLED) 16675331Samw return (ACLENT_T); 16685331Samw 16695331Samw return (ACE_T); 16705331Samw } 16715331Samw 16725331Samw static int zfs_perms[] = { 16735331Samw ACE_READ_DATA, ACE_WRITE_DATA, ACE_APPEND_DATA, ACE_READ_NAMED_ATTRS, 16745331Samw ACE_WRITE_NAMED_ATTRS, ACE_EXECUTE, ACE_DELETE_CHILD, 16755331Samw ACE_READ_ATTRIBUTES, ACE_WRITE_ATTRIBUTES, ACE_DELETE, ACE_READ_ACL, 16765331Samw ACE_WRITE_ACL, ACE_WRITE_OWNER, ACE_SYNCHRONIZE 16775331Samw }; 16785331Samw 16795331Samw static int unix_perms[] = { VREAD, VWRITE, VEXEC }; 16805331Samw /* 16815331Samw * smb_vop_eaccess 16825331Samw * 16835331Samw * Returns the effective permission of the given credential for the 16845331Samw * specified object. 16855331Samw * 16865331Samw * This is just a workaround. We need VFS/FS support for this. 16875331Samw */ 16885331Samw void 16895331Samw smb_vop_eaccess(vnode_t *vp, int *mode, int flags, vnode_t *dir_vp, cred_t *cr) 16905331Samw { 16915331Samw int error, i; 16925331Samw int pnum; 16935331Samw 16945331Samw *mode = 0; 16955331Samw 16965331Samw if (flags == V_ACE_MASK) { 16975331Samw pnum = sizeof (zfs_perms) / sizeof (int); 16985331Samw 16995331Samw for (i = 0; i < pnum; i++) { 17005331Samw error = smb_vop_access(vp, zfs_perms[i], flags, 17015331Samw dir_vp, cr); 17025331Samw if (error == 0) 17035331Samw *mode |= zfs_perms[i]; 17045331Samw } 17055331Samw } else { 17065331Samw pnum = sizeof (unix_perms) / sizeof (int); 17075331Samw 17085331Samw for (i = 0; i < pnum; i++) { 17095331Samw error = smb_vop_access(vp, unix_perms[i], flags, 17105331Samw dir_vp, cr); 17115331Samw if (error == 0) 17125331Samw *mode |= unix_perms[i]; 17135331Samw } 17145331Samw } 17155331Samw } 1716