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 /* 225772Sas200622 * Copyright 2008 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> 375772Sas200622 #include <sys/nbmlock.h> 385772Sas200622 #include <sys/share.h> 395772Sas200622 #include <sys/fcntl.h> 40*6139Sjb150015 #include <nfs/lm.h> 415521Sas200622 425331Samw #include <smbsrv/smb_vops.h> 435331Samw #include <smbsrv/string.h> 445521Sas200622 455331Samw #include <smbsrv/smbtrans.h> 465521Sas200622 #include <smbsrv/smb_fsops.h> 475521Sas200622 #include <smbsrv/smb_kproto.h> 485331Samw #include <smbsrv/smb_incl.h> 495521Sas200622 505772Sas200622 void 515772Sas200622 smb_vop_setup_xvattr(smb_attr_t *smb_attr, xvattr_t *xvattr); 525331Samw 535331Samw static int 54*6139Sjb150015 smb_vop_readdir_readpage(vnode_t *, void *, uint32_t, int *, cred_t *, int); 555331Samw 565331Samw static int 57*6139Sjb150015 smb_vop_readdir_entry(vnode_t *, uint32_t *, char *, int *, 58*6139Sjb150015 ino64_t *, vnode_t **, char *, int, cred_t *, char *, int); 595331Samw 605331Samw static int 61*6139Sjb150015 smb_vop_getdents_entries(smb_node_t *, uint32_t *, int32_t *, char *, uint32_t, 62*6139Sjb150015 smb_request_t *, cred_t *, char *, int *, int, char *); 635331Samw 645331Samw extern int 655331Samw smb_gather_dents_info(char *args, ino_t fileid, int namelen, 665331Samw char *name, uint32_t cookie, int32_t *countp, 675331Samw smb_attr_t *attr, struct smb_node *snode, 685331Samw char *shortname, char *name83); 695331Samw 705331Samw static void 715331Samw smb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp); 725331Samw 735772Sas200622 extern sysid_t lm_alloc_sysidt(); 745772Sas200622 755331Samw #define SMB_AT_MAX 16 765331Samw static uint_t smb_attrmap[SMB_AT_MAX] = { 775331Samw 0, 785331Samw AT_TYPE, 795331Samw AT_MODE, 805331Samw AT_UID, 815331Samw AT_GID, 825331Samw AT_FSID, 835331Samw AT_NODEID, 845331Samw AT_NLINK, 855331Samw AT_SIZE, 865331Samw AT_ATIME, 875331Samw AT_MTIME, 885331Samw AT_CTIME, 895331Samw AT_RDEV, 905331Samw AT_BLKSIZE, 915331Samw AT_NBLOCKS, 925331Samw AT_SEQ 935331Samw }; 945331Samw 95*6139Sjb150015 static boolean_t smb_vop_initialized = B_FALSE; 96*6139Sjb150015 caller_context_t smb_ct; 97*6139Sjb150015 98*6139Sjb150015 /* 99*6139Sjb150015 * smb_vop_init 100*6139Sjb150015 * 101*6139Sjb150015 * This function is not multi-thread safe. The caller must make sure only one 102*6139Sjb150015 * thread makes the call. 103*6139Sjb150015 */ 104*6139Sjb150015 int 105*6139Sjb150015 smb_vop_init(void) 106*6139Sjb150015 { 107*6139Sjb150015 if (smb_vop_initialized) 108*6139Sjb150015 return (0); 109*6139Sjb150015 /* 110*6139Sjb150015 * The caller_context will be used primarily for range locking. 111*6139Sjb150015 * Since the CIFS server is mapping its locks to POSIX locks, 112*6139Sjb150015 * only one pid is used for operations originating from the 113*6139Sjb150015 * CIFS server (to represent CIFS in the VOP_FRLOCK routines). 114*6139Sjb150015 */ 115*6139Sjb150015 smb_ct.cc_sysid = lm_alloc_sysidt(); 116*6139Sjb150015 if (smb_ct.cc_sysid == LM_NOSYSID) 117*6139Sjb150015 return (ENOMEM); 118*6139Sjb150015 119*6139Sjb150015 smb_ct.cc_caller_id = fs_new_caller_id(); 120*6139Sjb150015 smb_ct.cc_pid = 0; 121*6139Sjb150015 smb_ct.cc_flags = 0; 122*6139Sjb150015 123*6139Sjb150015 smb_vop_initialized = B_TRUE; 124*6139Sjb150015 return (0); 125*6139Sjb150015 } 126*6139Sjb150015 127*6139Sjb150015 /* 128*6139Sjb150015 * smb_vop_fini 129*6139Sjb150015 * 130*6139Sjb150015 * This function is not multi-thread safe. The caller must make sure only one 131*6139Sjb150015 * thread makes the call. 132*6139Sjb150015 */ 133*6139Sjb150015 void 134*6139Sjb150015 smb_vop_fini(void) 135*6139Sjb150015 { 136*6139Sjb150015 if (!smb_vop_initialized) 137*6139Sjb150015 return; 138*6139Sjb150015 139*6139Sjb150015 lm_free_sysidt(smb_ct.cc_sysid); 140*6139Sjb150015 smb_ct.cc_sysid = LM_NOSYSID; 141*6139Sjb150015 smb_vop_initialized = B_FALSE; 142*6139Sjb150015 } 143*6139Sjb150015 1445772Sas200622 /* 1455772Sas200622 * The smb_ct will be used primarily for range locking. 1465772Sas200622 * Since the CIFS server is mapping its locks to POSIX locks, 1475772Sas200622 * only one pid is used for operations originating from the 1485772Sas200622 * CIFS server (to represent CIFS in the VOP_FRLOCK routines). 1495772Sas200622 */ 1505772Sas200622 1515331Samw int 1525772Sas200622 smb_vop_open(vnode_t **vpp, int mode, cred_t *cred) 1535331Samw { 1545772Sas200622 return (VOP_OPEN(vpp, mode, cred, &smb_ct)); 1555772Sas200622 } 1565772Sas200622 1575772Sas200622 int 1585772Sas200622 smb_vop_close(vnode_t *vp, int mode, cred_t *cred) 1595772Sas200622 { 1605772Sas200622 return (VOP_CLOSE(vp, mode, 1, (offset_t)0, cred, &smb_ct)); 1615331Samw } 1625331Samw 1635331Samw /* 1645331Samw * The smb_vop_* functions have minimal knowledge of CIFS semantics and 1655331Samw * serve as an interface to the VFS layer. 1665331Samw * 1675331Samw * Only smb_fsop_* layer functions should call smb_vop_* layer functions. 1685331Samw * (Higher-level CIFS service code should never skip the smb_fsop_* layer 1695331Samw * to call smb_vop_* layer functions directly.) 1705331Samw */ 1715331Samw 1725331Samw /* 1735331Samw * XXX - Extended attributes support in the file system assumed. 1745331Samw * This is needed for full NT Streams functionality. 1755331Samw */ 1765331Samw 1775331Samw int 1785772Sas200622 smb_vop_read(vnode_t *vp, uio_t *uiop, cred_t *cr) 1795331Samw { 1805331Samw int error; 1815331Samw 1825331Samw (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL); 1835772Sas200622 error = VOP_READ(vp, uiop, 0, cr, &smb_ct); 1845331Samw VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 1855331Samw return (error); 1865331Samw } 1875331Samw 1885331Samw int 1895331Samw smb_vop_write(vnode_t *vp, uio_t *uiop, uint32_t *flag, uint32_t *lcount, 1905772Sas200622 cred_t *cr) 1915331Samw { 1925331Samw int error; 1935331Samw int ioflag = 0; 1945331Samw 1955331Samw *lcount = uiop->uio_resid; 1965331Samw 1975331Samw if (*flag == FSSTAB_FILE_SYNC) 1985331Samw ioflag = FSYNC; 1995331Samw 2005331Samw uiop->uio_llimit = MAXOFFSET_T; 2015331Samw 2025331Samw (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); 2035772Sas200622 error = VOP_WRITE(vp, uiop, ioflag, cr, &smb_ct); 2045331Samw VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 2055331Samw 2065331Samw *lcount -= uiop->uio_resid; 2075331Samw 2085331Samw return (error); 2095331Samw } 2105331Samw 2115331Samw /* 2125331Samw * smb_vop_getattr() 2135331Samw * 2145331Samw * smb_fsop_getattr()/smb_vop_getattr() should always be called from the CIFS 2155331Samw * service (instead of calling VOP_GETATTR directly) to retrieve attributes 2165331Samw * due to special processing needed for streams files. 2175331Samw * 2185331Samw * All attributes are retrieved. 2195331Samw * 2205331Samw * A named stream's attributes (as far as CIFS is concerned) are those of the 2215331Samw * unnamed (i.e. data) stream (minus the size attribute), and the size of the 2225331Samw * named stream. Though the file system may store attributes other than size 2235331Samw * with the named stream, these should not be used by CIFS for any purpose. 2245331Samw * 2255331Samw * When vp denotes a named stream, then unnamed_vp should be passed in (denoting 2265331Samw * the corresponding unnamed stream). 2275331Samw */ 2285331Samw 2295331Samw int 2305331Samw smb_vop_getattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *ret_attr, 2315772Sas200622 int flags, cred_t *cr) 2325331Samw { 2335331Samw int error; 2345331Samw vnode_t *use_vp; 2355331Samw smb_attr_t tmp_attr; 2365331Samw xvattr_t tmp_xvattr; 2375331Samw xoptattr_t *xoap = NULL; 2385331Samw 2395331Samw if (unnamed_vp) 2405331Samw use_vp = unnamed_vp; 2415331Samw else 2425331Samw use_vp = vp; 2435331Samw 2445331Samw if (vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) { 2455331Samw xva_init(&tmp_xvattr); 2465331Samw xoap = xva_getxoptattr(&tmp_xvattr); 2475331Samw 2485331Samw ASSERT(xoap); 2495331Samw 2505331Samw smb_sa_to_va_mask(ret_attr->sa_mask, 2515331Samw &tmp_xvattr.xva_vattr.va_mask); 2525331Samw 2535331Samw XVA_SET_REQ(&tmp_xvattr, XAT_READONLY); 2545331Samw XVA_SET_REQ(&tmp_xvattr, XAT_HIDDEN); 2555331Samw XVA_SET_REQ(&tmp_xvattr, XAT_SYSTEM); 2565331Samw XVA_SET_REQ(&tmp_xvattr, XAT_ARCHIVE); 2575331Samw XVA_SET_REQ(&tmp_xvattr, XAT_CREATETIME); 2585331Samw 2595331Samw if ((error = VOP_GETATTR(use_vp, (vattr_t *)&tmp_xvattr, flags, 2605772Sas200622 cr, &smb_ct)) != 0) 2615331Samw return (error); 2625331Samw 2635331Samw ret_attr->sa_vattr = tmp_xvattr.xva_vattr; 2645331Samw 2655331Samw /* 2665331Samw * Copy special attributes to ret_attr parameter 2675331Samw */ 2685331Samw 2695331Samw ret_attr->sa_dosattr = 0; 2705331Samw 2715331Samw ASSERT(tmp_xvattr.xva_vattr.va_mask & AT_XVATTR); 2725331Samw 2735331Samw xoap = xva_getxoptattr(&tmp_xvattr); 2745331Samw ASSERT(xoap); 2755331Samw 2765331Samw if (XVA_ISSET_RTN(&tmp_xvattr, XAT_READONLY)) { 2775331Samw if (xoap->xoa_readonly) 2785331Samw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_READONLY; 2795331Samw } 2805331Samw 2815331Samw if (XVA_ISSET_RTN(&tmp_xvattr, XAT_HIDDEN)) { 2825331Samw if (xoap->xoa_hidden) 2835331Samw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_HIDDEN; 2845331Samw } 2855331Samw 2865331Samw if (XVA_ISSET_RTN(&tmp_xvattr, XAT_SYSTEM)) { 2875331Samw if (xoap->xoa_system) 2885331Samw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_SYSTEM; 2895331Samw } 2905331Samw 2915331Samw if (XVA_ISSET_RTN(&tmp_xvattr, XAT_ARCHIVE)) { 2925331Samw if (xoap->xoa_archive) 2935331Samw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_ARCHIVE; 2945331Samw } 2955331Samw 2965331Samw ret_attr->sa_crtime = xoap->xoa_createtime; 2975331Samw 2985331Samw if (unnamed_vp && (ret_attr->sa_mask & SMB_AT_SIZE)) { 2995331Samw /* 3005331Samw * Retrieve stream size attribute into temporary 3015331Samw * structure, in case the underlying file system 3025331Samw * returns attributes other than the size (we do not 3035331Samw * want to have ret_attr's other fields get 3045331Samw * overwritten). 3055331Samw * 3065331Samw * Note that vp is used here, and not use_vp. 3075331Samw * Also, only AT_SIZE is needed. 3085331Samw */ 3095331Samw 3105331Samw tmp_xvattr.xva_vattr.va_mask = AT_SIZE; 3115331Samw 3125331Samw if ((error = VOP_GETATTR(vp, (vattr_t *)&tmp_xvattr, 3135772Sas200622 flags, cr, &smb_ct)) != 0) 3145331Samw return (error); 3155331Samw 3165331Samw ret_attr->sa_vattr.va_size = 3175331Samw tmp_xvattr.xva_vattr.va_size; 3185331Samw 3195331Samw } 3205331Samw 3215331Samw if (ret_attr->sa_vattr.va_type == VDIR) { 3225331Samw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY; 3235331Samw } 3245331Samw 3255331Samw return (error); 3265331Samw } 3275331Samw 3285331Samw /* 3295331Samw * Support for file systems without VFSFT_XVATTR 3305331Samw */ 3315331Samw 3325331Samw smb_sa_to_va_mask(ret_attr->sa_mask, 3335331Samw &ret_attr->sa_vattr.va_mask); 3345331Samw 3355772Sas200622 error = VOP_GETATTR(use_vp, &ret_attr->sa_vattr, flags, cr, &smb_ct); 3365331Samw 3375331Samw if (error != 0) 3385331Samw return (error); 3395331Samw 3405331Samw /* 3415331Samw * "Fake" DOS attributes and create time, filesystem doesn't support 3425331Samw * them. 3435331Samw */ 3445331Samw 3455331Samw ret_attr->sa_dosattr = 0; 3465331Samw ret_attr->sa_crtime = ret_attr->sa_vattr.va_ctime; 3475331Samw 3485331Samw if (unnamed_vp && (ret_attr->sa_mask & SMB_AT_SIZE)) { 3495331Samw /* 3505331Samw * Retrieve stream size attribute into temporary structure, 3515331Samw * in case the underlying file system returns attributes 3525331Samw * other than the size (we do not want to have ret_attr's 3535331Samw * other fields get overwritten). 3545331Samw * 3555331Samw * Note that vp is used here, and not use_vp. 3565331Samw * Also, only AT_SIZE is needed. 3575331Samw */ 3585331Samw 3595331Samw tmp_attr.sa_vattr.va_mask = AT_SIZE; 3605772Sas200622 error = VOP_GETATTR(vp, &tmp_attr.sa_vattr, flags, cr, &smb_ct); 3615331Samw 3625331Samw if (error != 0) 3635331Samw return (error); 3645331Samw 3655331Samw 3665331Samw ret_attr->sa_vattr.va_size = tmp_attr.sa_vattr.va_size; 3675331Samw } 3685331Samw 3695331Samw if (ret_attr->sa_vattr.va_type == VDIR) { 3705331Samw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY; 3715331Samw } 3725331Samw 3735331Samw return (error); 3745331Samw } 3755331Samw 3765331Samw /* 3775331Samw * smb_vop_setattr() 3785331Samw * 3796030Sjb150015 * smb_fsop_setattr()/smb_vop_setattr() should always be used instead of 3806030Sjb150015 * VOP_SETATTR() when calling from the CIFS service, due to special processing 3816030Sjb150015 * for streams files. 3825331Samw * 3836030Sjb150015 * Streams have a size but otherwise do not have separate attributes from 3846030Sjb150015 * the (unnamed stream) file, i.e., the security and ownership of the file 3856030Sjb150015 * applies to the stream. In contrast, extended attribute files, which are 3866030Sjb150015 * used to implement streams, are independent objects with their own 3876030Sjb150015 * attributes. 3886030Sjb150015 * 3896030Sjb150015 * For compatibility with streams, we set the size on the extended attribute 3906030Sjb150015 * file and apply other attributes to the (unnamed stream) file. The one 3916030Sjb150015 * exception is that the UID and GID can be set on the stream by passing a 3926030Sjb150015 * NULL unnamed_vp, which allows callers to synchronize stream ownership 3936030Sjb150015 * with the (unnamed stream) file. 3945331Samw */ 3955331Samw 3965331Samw int 3975331Samw smb_vop_setattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *set_attr, 3985772Sas200622 int flags, cred_t *cr, boolean_t no_xvattr) 3995331Samw { 4005331Samw int error = 0; 4015331Samw int at_size = 0; 4025331Samw vnode_t *use_vp; 4035772Sas200622 xvattr_t xvattr; 4045772Sas200622 vattr_t *vap; 4055331Samw 4065331Samw if (unnamed_vp) { 4075331Samw use_vp = unnamed_vp; 4085331Samw if (set_attr->sa_mask & SMB_AT_SIZE) { 4095331Samw at_size = 1; 4105331Samw set_attr->sa_mask &= ~SMB_AT_SIZE; 4115331Samw } 4125331Samw } else { 4135331Samw use_vp = vp; 4145331Samw } 4155331Samw 4165331Samw /* 4175331Samw * The caller should not be setting sa_vattr.va_mask, 4185331Samw * but rather sa_mask. 4195331Samw */ 4205331Samw 4215331Samw set_attr->sa_vattr.va_mask = 0; 4225331Samw 4235521Sas200622 if ((no_xvattr == B_FALSE) && 4245521Sas200622 vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) { 4255331Samw 4265772Sas200622 smb_vop_setup_xvattr(set_attr, &xvattr); 4275772Sas200622 vap = (vattr_t *)&xvattr; 4285772Sas200622 } else { 4295331Samw smb_sa_to_va_mask(set_attr->sa_mask, 4305772Sas200622 &set_attr->sa_vattr.va_mask); 4315772Sas200622 vap = &set_attr->sa_vattr; 4325772Sas200622 } 4335331Samw 4345772Sas200622 if ((error = VOP_SETATTR(use_vp, vap, flags, cr, &smb_ct)) != 0) 4355772Sas200622 return (error); 4365331Samw 4375331Samw /* 4385772Sas200622 * If the size of the stream needs to be set, set it on 4395772Sas200622 * the stream file directly. (All other indicated attributes 4406030Sjb150015 * are set on the stream's unnamed stream, except under the 4416030Sjb150015 * exception described in the function header.) 4425331Samw */ 4435331Samw 4445331Samw if (at_size) { 4455331Samw /* 4465331Samw * set_attr->sa_vattr.va_size already contains the 4475331Samw * size as set by the caller 4485331Samw * 4495331Samw * Note that vp is used here, and not use_vp. 4505331Samw * Also, only AT_SIZE is needed. 4515331Samw */ 4525331Samw 4535331Samw set_attr->sa_vattr.va_mask = AT_SIZE; 4545772Sas200622 error = VOP_SETATTR(vp, &set_attr->sa_vattr, flags, cr, 4555772Sas200622 &smb_ct); 4565331Samw } 4575772Sas200622 4585331Samw return (error); 4595331Samw } 4605331Samw 4615331Samw /* 4625331Samw * smb_vop_access 4635331Samw * 4645331Samw * This is a wrapper round VOP_ACCESS. VOP_ACCESS checks the given mode 4655331Samw * against file's ACL or Unix permissions. CIFS on the other hand needs to 4665331Samw * know if the requested operation can succeed for the given object, this 4675331Samw * requires more checks in case of DELETE bit since permissions on the parent 4685331Samw * directory are important as well. Based on Windows rules if parent's ACL 4695331Samw * grant FILE_DELETE_CHILD a file can be delete regardless of the file's 4705331Samw * permissions. 4715331Samw */ 4725331Samw int 4735331Samw smb_vop_access(vnode_t *vp, int mode, int flags, vnode_t *dir_vp, cred_t *cr) 4745331Samw { 4755331Samw int error = 0; 4765331Samw 4775331Samw if (mode == 0) 4785331Samw return (0); 4795331Samw 4805331Samw if ((flags == V_ACE_MASK) && (mode & ACE_DELETE)) { 4815331Samw if (dir_vp) { 4825331Samw error = VOP_ACCESS(dir_vp, ACE_DELETE_CHILD, flags, 4835331Samw cr, NULL); 4845331Samw 4855331Samw if (error == 0) 4865331Samw mode &= ~ACE_DELETE; 4875331Samw } 4885331Samw } 4895331Samw 4905331Samw if (mode) { 4915331Samw error = VOP_ACCESS(vp, mode, flags, cr, NULL); 4925331Samw } 4935331Samw 4945331Samw return (error); 4955331Samw } 4965331Samw 4975331Samw /* 4985331Samw * smb_vop_lookup 4995331Samw * 5005331Samw * dvp: directory vnode (in) 5015331Samw * name: name of file to be looked up (in) 5025331Samw * vpp: looked-up vnode (out) 5035331Samw * od_name: on-disk name of file (out). 5045331Samw * This parameter is optional. If a pointer is passed in, it 5055331Samw * must be allocated with MAXNAMELEN bytes 5065331Samw * rootvp: vnode of the tree root (in) 5075331Samw * This parameter is always passed in non-NULL except at the time 5085331Samw * of share set up. 5095331Samw */ 5105331Samw 5115331Samw int 512*6139Sjb150015 smb_vop_lookup( 513*6139Sjb150015 vnode_t *dvp, 514*6139Sjb150015 char *name, 515*6139Sjb150015 vnode_t **vpp, 516*6139Sjb150015 char *od_name, 517*6139Sjb150015 int flags, 518*6139Sjb150015 vnode_t *rootvp, 519*6139Sjb150015 cred_t *cr) 5205331Samw { 5215331Samw int error = 0; 5225331Samw int option_flags = 0; 5235331Samw pathname_t rpn; 5245331Samw 5255331Samw if (*name == '\0') 5265331Samw return (EINVAL); 5275331Samw 5285331Samw ASSERT(vpp); 5295331Samw *vpp = NULL; 5305331Samw 5315331Samw if ((name[0] == '.') && (name[1] == '.') && (name[2] == 0)) { 5325331Samw if (rootvp && (dvp == rootvp)) { 5335331Samw VN_HOLD(dvp); 5345331Samw *vpp = dvp; 5355331Samw return (0); 5365331Samw } 5375331Samw 5385331Samw if (dvp->v_flag & VROOT) { 5395331Samw vfs_t *vfsp; 5405331Samw vnode_t *cvp = dvp; 5415331Samw 5425331Samw /* 5435331Samw * Set dvp and check for races with forced unmount 5445331Samw * (see lookuppnvp()) 5455331Samw */ 5465331Samw 5475331Samw vfsp = cvp->v_vfsp; 5485331Samw vfs_rlock_wait(vfsp); 5495331Samw if (((dvp = cvp->v_vfsp->vfs_vnodecovered) == NULL) || 5505331Samw (cvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)) { 5515331Samw vfs_unlock(vfsp); 5525331Samw return (EIO); 5535331Samw } 5545331Samw vfs_unlock(vfsp); 5555331Samw } 5565331Samw } 5575331Samw 5585331Samw 5595331Samw 5605331Samw if (flags & SMB_IGNORE_CASE) 5615331Samw option_flags = FIGNORECASE; 5625331Samw 5635331Samw pn_alloc(&rpn); 5645331Samw 5655331Samw error = VOP_LOOKUP(dvp, name, vpp, NULL, option_flags, NULL, cr, 5665772Sas200622 &smb_ct, NULL, &rpn); 5675331Samw 5685331Samw if ((error == 0) && od_name) { 5695331Samw bzero(od_name, MAXNAMELEN); 5705331Samw if (option_flags == FIGNORECASE) 5715331Samw (void) strlcpy(od_name, rpn.pn_buf, MAXNAMELEN); 5725331Samw else 5735331Samw (void) strlcpy(od_name, name, MAXNAMELEN); 5745331Samw } 5755331Samw 5765331Samw pn_free(&rpn); 5775331Samw return (error); 5785331Samw } 5795331Samw 5805331Samw int 5815331Samw smb_vop_create(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp, 5825772Sas200622 int flags, cred_t *cr, vsecattr_t *vsap) 5835772Sas200622 { 5845772Sas200622 int error; 5855772Sas200622 int option_flags = 0; 5865772Sas200622 xvattr_t xvattr; 5875772Sas200622 vattr_t *vap; 5885772Sas200622 5895772Sas200622 if (flags & SMB_IGNORE_CASE) 5905772Sas200622 option_flags = FIGNORECASE; 5915772Sas200622 5925772Sas200622 attr->sa_vattr.va_mask = 0; 5935772Sas200622 5945772Sas200622 if (vfs_has_feature(dvp->v_vfsp, VFSFT_XVATTR)) { 5955772Sas200622 smb_vop_setup_xvattr(attr, &xvattr); 5965772Sas200622 vap = (vattr_t *)&xvattr; 5975772Sas200622 } else { 5985772Sas200622 smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask); 5995772Sas200622 vap = &attr->sa_vattr; 6005772Sas200622 } 6015772Sas200622 6025772Sas200622 error = VOP_CREATE(dvp, name, vap, EXCL, attr->sa_vattr.va_mode, 6035772Sas200622 vpp, cr, option_flags, &smb_ct, vsap); 6045772Sas200622 6055772Sas200622 return (error); 6065772Sas200622 } 6075772Sas200622 6085772Sas200622 int 6095772Sas200622 smb_vop_remove(vnode_t *dvp, char *name, int flags, cred_t *cr) 6105331Samw { 6115331Samw int error; 6125331Samw int option_flags = 0; 6135331Samw 6145331Samw if (flags & SMB_IGNORE_CASE) 6155331Samw option_flags = FIGNORECASE; 6165331Samw 6175772Sas200622 error = VOP_REMOVE(dvp, name, cr, &smb_ct, option_flags); 6185331Samw 6195331Samw return (error); 6205331Samw } 6215331Samw 6225331Samw /* 6235331Samw * smb_vop_rename() 6245331Samw * 6255331Samw * The rename is for files in the same tree (identical TID) only. 6265331Samw */ 6275331Samw 6285331Samw int 6295331Samw smb_vop_rename(vnode_t *from_dvp, char *from_name, vnode_t *to_dvp, 6305772Sas200622 char *to_name, int flags, cred_t *cr) 6315331Samw { 6325331Samw int error; 6335331Samw int option_flags = 0; 6345331Samw 6355331Samw 6365331Samw if (flags & SMB_IGNORE_CASE) 6375331Samw option_flags = FIGNORECASE; 6385331Samw 6395331Samw error = VOP_RENAME(from_dvp, from_name, to_dvp, to_name, cr, 6405772Sas200622 &smb_ct, option_flags); 6415331Samw 6425331Samw return (error); 6435331Samw } 6445331Samw 6455331Samw int 6465331Samw smb_vop_mkdir(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp, 6475772Sas200622 int flags, cred_t *cr, vsecattr_t *vsap) 6485331Samw { 6495331Samw int error; 6505331Samw int option_flags = 0; 6515331Samw 6525331Samw 6535331Samw 6545331Samw if (flags & SMB_IGNORE_CASE) 6555331Samw option_flags = FIGNORECASE; 6565331Samw 6575331Samw smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask); 6585331Samw 6595772Sas200622 error = VOP_MKDIR(dvp, name, &attr->sa_vattr, vpp, cr, &smb_ct, 6605331Samw option_flags, vsap); 6615331Samw 6625331Samw return (error); 6635331Samw } 6645331Samw 6655331Samw /* 6665331Samw * smb_vop_rmdir() 6675331Samw * 6685331Samw * Only simple rmdir supported, consistent with NT semantics 6695331Samw * (can only remove an empty directory). 6705331Samw * 6715331Samw */ 6725331Samw 6735331Samw int 6745772Sas200622 smb_vop_rmdir(vnode_t *dvp, char *name, int flags, cred_t *cr) 6755331Samw { 6765331Samw int error; 6775331Samw int option_flags = 0; 6785331Samw 6795331Samw if (flags & SMB_IGNORE_CASE) 6805331Samw option_flags = FIGNORECASE; 6815331Samw 6825331Samw /* 6835331Samw * Comments adapted from rfs_rmdir(). 6845331Samw * 6855331Samw * VOP_RMDIR now takes a new third argument (the current 6865331Samw * directory of the process). That's because rmdir 6875331Samw * wants to return EINVAL if one tries to remove ".". 6885331Samw * Of course, SMB servers do not know what their 6895331Samw * clients' current directories are. We fake it by 6905331Samw * supplying a vnode known to exist and illegal to 6915331Samw * remove. 6925331Samw */ 6935331Samw 6945772Sas200622 error = VOP_RMDIR(dvp, name, rootdir, cr, &smb_ct, option_flags); 6955331Samw return (error); 6965331Samw } 6975331Samw 6985331Samw int 6995772Sas200622 smb_vop_commit(vnode_t *vp, cred_t *cr) 7005772Sas200622 { 7015772Sas200622 return (VOP_FSYNC(vp, 1, cr, &smb_ct)); 7025772Sas200622 } 7035772Sas200622 7045772Sas200622 void 7055772Sas200622 smb_vop_setup_xvattr(smb_attr_t *smb_attr, xvattr_t *xvattr) 7065331Samw { 7075772Sas200622 xoptattr_t *xoap = NULL; 7085772Sas200622 uint_t xva_mask; 7095772Sas200622 7105772Sas200622 /* 7115772Sas200622 * Initialize xvattr, including bzero 7125772Sas200622 */ 7135772Sas200622 xva_init(xvattr); 7145772Sas200622 xoap = xva_getxoptattr(xvattr); 7155772Sas200622 7165772Sas200622 ASSERT(xoap); 7175772Sas200622 7185772Sas200622 /* 7195772Sas200622 * Copy caller-specified classic attributes to xvattr. 7205772Sas200622 * First save xvattr's mask (set in xva_init()), which 7215772Sas200622 * contains AT_XVATTR. This is |'d in later if needed. 7225772Sas200622 */ 7235772Sas200622 7245772Sas200622 xva_mask = xvattr->xva_vattr.va_mask; 7255772Sas200622 xvattr->xva_vattr = smb_attr->sa_vattr; 7265772Sas200622 7275772Sas200622 smb_sa_to_va_mask(smb_attr->sa_mask, &xvattr->xva_vattr.va_mask); 7285772Sas200622 7295772Sas200622 /* 7305772Sas200622 * Do not set ctime (only the file system can do it) 7315772Sas200622 */ 7325772Sas200622 7335772Sas200622 xvattr->xva_vattr.va_mask &= ~AT_CTIME; 7345772Sas200622 7355772Sas200622 if (smb_attr->sa_mask & SMB_AT_DOSATTR) { 7365772Sas200622 7375772Sas200622 /* 7385772Sas200622 * "|" in the original xva_mask, which contains 7395772Sas200622 * AT_XVATTR 7405772Sas200622 */ 7415772Sas200622 7425772Sas200622 xvattr->xva_vattr.va_mask |= xva_mask; 7435772Sas200622 7445772Sas200622 XVA_SET_REQ(xvattr, XAT_ARCHIVE); 7455772Sas200622 XVA_SET_REQ(xvattr, XAT_SYSTEM); 7465772Sas200622 XVA_SET_REQ(xvattr, XAT_READONLY); 7475772Sas200622 XVA_SET_REQ(xvattr, XAT_HIDDEN); 7485772Sas200622 7495772Sas200622 /* 7505772Sas200622 * smb_attr->sa_dosattr: If a given bit is not set, 7515772Sas200622 * that indicates that the corresponding field needs 7525772Sas200622 * to be updated with a "0" value. This is done 7535772Sas200622 * implicitly as the xoap->xoa_* fields were bzero'd. 7545772Sas200622 */ 7555772Sas200622 7565772Sas200622 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_ARCHIVE) 7575772Sas200622 xoap->xoa_archive = 1; 7585772Sas200622 7595772Sas200622 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_SYSTEM) 7605772Sas200622 xoap->xoa_system = 1; 7615772Sas200622 7625772Sas200622 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_READONLY) 7635772Sas200622 xoap->xoa_readonly = 1; 7645772Sas200622 7655772Sas200622 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_HIDDEN) 7665772Sas200622 xoap->xoa_hidden = 1; 7675772Sas200622 } 7685772Sas200622 7695772Sas200622 if (smb_attr->sa_mask & SMB_AT_CRTIME) { 7705772Sas200622 /* 7715772Sas200622 * "|" in the original xva_mask, which contains 7725772Sas200622 * AT_XVATTR 7735772Sas200622 */ 7745772Sas200622 7755772Sas200622 xvattr->xva_vattr.va_mask |= xva_mask; 7765772Sas200622 XVA_SET_REQ(xvattr, XAT_CREATETIME); 7775772Sas200622 xoap->xoa_createtime = smb_attr->sa_crtime; 7785772Sas200622 } 7795331Samw } 7805331Samw 7815772Sas200622 7825331Samw /* 7835331Samw * smb_vop_readdir() 7845331Samw * 7855331Samw * Upon return, the "name" field will contain either the on-disk name or, if 7865331Samw * it needs mangling or has a case-insensitive collision, the mangled 7875331Samw * "shortname." 7885331Samw * 7895331Samw * vpp is an optional parameter. If non-NULL, it will contain a pointer to 7905331Samw * the vnode for the name that is looked up (the vnode will be returned held). 7915331Samw * 7925331Samw * od_name is an optional parameter (NULL can be passed if the on-disk name 7935331Samw * is not needed by the caller). 7945331Samw */ 7955331Samw 7965331Samw int 7975331Samw smb_vop_readdir(vnode_t *dvp, uint32_t *cookiep, char *name, int *namelen, 7985772Sas200622 ino64_t *inop, vnode_t **vpp, char *od_name, int flags, cred_t *cr) 7995331Samw { 8005331Samw int num_bytes; 8015331Samw int error = 0; 8025331Samw char *dirbuf = NULL; 8035331Samw 8045331Samw ASSERT(dvp); 8055331Samw ASSERT(cookiep); 8065331Samw ASSERT(name); 8075331Samw ASSERT(namelen); 8085331Samw ASSERT(inop); 8095331Samw ASSERT(cr); 8105331Samw 8115331Samw if (dvp->v_type != VDIR) { 8125331Samw *namelen = 0; 8135331Samw return (ENOTDIR); 8145331Samw } 8155331Samw 8165331Samw if (vpp) 8175331Samw *vpp = NULL; 8185331Samw 8195331Samw dirbuf = kmem_zalloc(SMB_MINLEN_RDDIR_BUF, KM_SLEEP); 8205331Samw num_bytes = SMB_MINLEN_RDDIR_BUF; 8215331Samw 8225331Samw /* 8235331Samw * The goal is to retrieve the first valid entry from *cookiep 8245331Samw * forward. smb_vop_readdir_readpage() collects an 8255331Samw * SMB_MINLEN_RDDIR_BUF-size "page" of directory entry information. 8265331Samw * smb_vop_readdir_entry() attempts to find the first valid entry 8275331Samw * in that page. 8285331Samw */ 8295331Samw 8305331Samw while ((error = smb_vop_readdir_readpage(dvp, dirbuf, *cookiep, 8315772Sas200622 &num_bytes, cr, flags)) == 0) { 8325331Samw 8335331Samw if (num_bytes <= 0) 8345331Samw break; 8355331Samw 8365331Samw name[0] = '\0'; 8375331Samw 8385331Samw error = smb_vop_readdir_entry(dvp, cookiep, name, namelen, 839*6139Sjb150015 inop, vpp, od_name, flags, cr, dirbuf, num_bytes); 8405331Samw 8415331Samw if (error) 8425331Samw break; 8435331Samw 8445331Samw if (*name) 8455331Samw break; 8465331Samw 8475331Samw bzero(dirbuf, SMB_MINLEN_RDDIR_BUF); 8485331Samw num_bytes = SMB_MINLEN_RDDIR_BUF; 8495331Samw } 8505331Samw 8515331Samw 8525331Samw if (error) { 8535331Samw kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 8545331Samw *namelen = 0; 8555331Samw return (error); 8565331Samw } 8575331Samw 8585331Samw if (num_bytes == 0) { /* EOF */ 8595331Samw kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 8605331Samw *cookiep = SMB_EOF; 8615331Samw *namelen = 0; 8625331Samw return (0); 8635331Samw } 8645331Samw 8655331Samw kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 8665331Samw return (0); 8675331Samw } 8685331Samw 8695331Samw /* 8705331Samw * smb_vop_readdir_readpage() 8715331Samw * 8725331Samw * Collects an SMB_MINLEN_RDDIR_BUF "page" of directory entries. (The 8735331Samw * directory entries are returned in an fs-independent format by the 8745331Samw * underlying file system. That is, the "page" of information returned is 8755331Samw * not literally stored on-disk in the format returned.) 8765331Samw * 8775331Samw * Much of the following is borrowed from getdents64() 8785331Samw * 8795331Samw * MAXGETDENTS_SIZE is defined in getdents.c 8805331Samw */ 8815331Samw 8825331Samw #define MAXGETDENTS_SIZE (64 * 1024) 8835331Samw 8845331Samw static int 8855331Samw smb_vop_readdir_readpage(vnode_t *vp, void *buf, uint32_t offset, int *count, 8865772Sas200622 cred_t *cr, int flags) 8875331Samw { 8885331Samw int error = 0; 8895331Samw int rdirent_flags = 0; 8905331Samw int sink; 8915331Samw struct uio auio; 8925331Samw struct iovec aiov; 8935331Samw 8945331Samw if (vp->v_type != VDIR) 8955331Samw return (ENOTDIR); 8965331Samw 8975331Samw /* entflags not working for streams so don't try to use them */ 8985331Samw if (!(flags & SMB_STREAM_RDDIR) && 8995331Samw (vfs_has_feature(vp->v_vfsp, VFSFT_DIRENTFLAGS))) { 9005331Samw /* 9015331Samw * Setting V_RDDIR_ENTFLAGS will cause the buffer to 9025331Samw * be filled with edirent_t structures (instead of 9035331Samw * dirent64_t structures). 9045331Samw */ 9055331Samw rdirent_flags = V_RDDIR_ENTFLAGS; 9065331Samw 9075331Samw if (*count < sizeof (edirent_t)) 9085331Samw return (EINVAL); 9095331Samw } else { 9105331Samw if (*count < sizeof (dirent64_t)) 9115331Samw return (EINVAL); 9125331Samw } 9135331Samw 9145331Samw if (*count > MAXGETDENTS_SIZE) 9155331Samw *count = MAXGETDENTS_SIZE; 9165331Samw 9175331Samw aiov.iov_base = buf; 9185331Samw aiov.iov_len = *count; 9195331Samw auio.uio_iov = &aiov; 9205331Samw auio.uio_iovcnt = 1; 9215331Samw auio.uio_loffset = (uint64_t)offset; 9225331Samw auio.uio_segflg = UIO_SYSSPACE; 9235331Samw auio.uio_resid = *count; 9245331Samw auio.uio_fmode = 0; 9255331Samw 9265331Samw (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL); 9275772Sas200622 error = VOP_READDIR(vp, &auio, cr, &sink, &smb_ct, rdirent_flags); 9285331Samw VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 9295331Samw 9305331Samw if (error) { 9315331Samw if (error == ENOENT) { 9325331Samw /* Fake EOF if offset is bad due to dropping of lock */ 9335331Samw *count = 0; 9345331Samw return (0); 9355331Samw } else { 9365331Samw return (error); 9375331Samw } 9385331Samw } 9395331Samw 9405331Samw /* 9415331Samw * Windows cannot handle an offset > SMB_EOF. 9425331Samw * Pretend we are at EOF. 9435331Samw */ 9445331Samw 9455331Samw if (auio.uio_loffset > SMB_EOF) { 9465331Samw *count = 0; 9475331Samw return (0); 9485331Samw } 9495331Samw 9505331Samw *count = *count - auio.uio_resid; 9515331Samw return (0); 9525331Samw } 9535331Samw 9545331Samw /* 9555331Samw * smb_vop_readdir_entry() 9565331Samw * 9575331Samw * This function retrieves the first valid entry from the 9585331Samw * SMB_MINLEN_RDDIR_BUF-sized buffer returned by smb_vop_readdir_readpage() 9595331Samw * to smb_vop_readdir(). 9605331Samw * 9615331Samw * Both dirent64_t and edirent_t structures need to be handled. The former is 9625331Samw * needed for file systems that do not support VFSFT_DIRENTFLAGS. The latter 9635331Samw * is required for proper handling of case collisions on file systems that 9645331Samw * support case-insensitivity. edirent_t structures are also used for 9655331Samw * case-sensitive file systems if VFSFT_DIRENTFLAGS is supported. 9665331Samw */ 9675331Samw 9685331Samw static int 969*6139Sjb150015 smb_vop_readdir_entry( 970*6139Sjb150015 vnode_t *dvp, 971*6139Sjb150015 uint32_t *cookiep, 972*6139Sjb150015 char *name, 973*6139Sjb150015 int *namelen, 974*6139Sjb150015 ino64_t *inop, 975*6139Sjb150015 vnode_t **vpp, 976*6139Sjb150015 char *od_name, 977*6139Sjb150015 int flags, 978*6139Sjb150015 cred_t *cr, 979*6139Sjb150015 char *dirbuf, 980*6139Sjb150015 int num_bytes) 9815331Samw { 9825331Samw uint32_t next_cookie; 9835331Samw int ebufsize; 9845331Samw int error = 0; 9855331Samw int len; 9865331Samw int rc; 9875331Samw char shortname[MANGLE_NAMELEN]; 9885331Samw char name83[MANGLE_NAMELEN]; 9895331Samw char *ebuf = NULL; 9905331Samw edirent_t *edp; 9915331Samw dirent64_t *dp = NULL; 9925331Samw vnode_t *vp = NULL; 9935331Samw 9945331Samw ASSERT(dirbuf); 9955331Samw 9965331Samw /* 9975331Samw * Use edirent_t structure for both 9985331Samw * entflags not working for streams so don't try to use them 9995331Samw */ 10005331Samw if (!(flags & SMB_STREAM_RDDIR) && 10015331Samw (vfs_has_feature(dvp->v_vfsp, VFSFT_DIRENTFLAGS))) { 10025331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 10035331Samw edp = (edirent_t *)dirbuf; 10045331Samw } else { 10055331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 10065331Samw dp = (dirent64_t *)dirbuf; 10075331Samw ebufsize = EDIRENT_RECLEN(MAXNAMELEN); 10085331Samw ebuf = kmem_zalloc(ebufsize, KM_SLEEP); 10095331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 10105331Samw edp = (edirent_t *)ebuf; 10115331Samw } 10125331Samw 10135331Samw while (edp) { 10145331Samw if (dp) 10155331Samw DP_TO_EDP(dp, edp); 10165331Samw 10175331Samw next_cookie = (uint32_t)edp->ed_off; 10185331Samw if (edp->ed_ino == 0) { 10195331Samw *cookiep = next_cookie; 10205331Samw 10215331Samw if (dp) { 10225331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 10235331Samw DP_ADVANCE(dp, dirbuf, num_bytes); 10245331Samw if (dp == NULL) 10255331Samw edp = NULL; 10265331Samw } else { 10275331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 10285331Samw EDP_ADVANCE(edp, dirbuf, num_bytes); 10295331Samw } 10305331Samw continue; 10315331Samw } 10325331Samw 10335331Samw len = strlen(edp->ed_name); 10345331Samw 10355331Samw if (*namelen < len) { 10365331Samw *namelen = 0; 10375331Samw 10385331Samw if (ebuf) 10395331Samw kmem_free(ebuf, ebufsize); 10405331Samw 10415331Samw return (EOVERFLOW); 10425331Samw } 10435331Samw 10445331Samw /* 10455331Samw * Do not pass SMB_IGNORE_CASE to smb_vop_lookup 10465331Samw */ 10475331Samw 10485331Samw error = smb_vop_lookup(dvp, edp->ed_name, vpp ? vpp : &vp, 10495772Sas200622 od_name, 0, NULL, cr); 10505331Samw 10515331Samw if (error) { 10525331Samw if (error == ENOENT) { 10535331Samw *cookiep = (uint32_t)next_cookie; 10545331Samw 10555331Samw if (dp) { 10565331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 10575331Samw DP_ADVANCE(dp, dirbuf, num_bytes); 10585331Samw if (dp == NULL) 10595331Samw edp = NULL; 10605331Samw } else { 10615331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 10625331Samw EDP_ADVANCE(edp, dirbuf, num_bytes); 10635331Samw } 10645331Samw continue; 10655331Samw } 10665331Samw 10675331Samw 10685331Samw *namelen = 0; 10695331Samw 10705331Samw if (ebuf) 10715331Samw kmem_free(ebuf, ebufsize); 10725331Samw 10735331Samw return (error); 10745331Samw } 10755331Samw 10765331Samw if ((flags & SMB_IGNORE_CASE) && ED_CASE_CONFLICTS(edp)) { 10775331Samw rc = smb_mangle_name(edp->ed_ino, edp->ed_name, 10785331Samw shortname, name83, 1); 10795331Samw 10805331Samw if (rc == 1) { /* success */ 10815331Samw (void) strlcpy(name, shortname, *namelen + 1); 10825331Samw *namelen = strlen(shortname); 10835331Samw } else { 10845331Samw (void) strlcpy(name, edp->ed_name, 10855331Samw *namelen + 1); 10865331Samw name[*namelen] = '\0'; 10875331Samw } 10885331Samw 10895331Samw } else { 10905331Samw (void) strlcpy(name, edp->ed_name, *namelen + 1); 10915331Samw *namelen = len; 10925331Samw } 10935331Samw 10945331Samw if (vpp == NULL) 10955331Samw VN_RELE(vp); 10965331Samw 10975331Samw if (inop) 10985331Samw *inop = edp->ed_ino; 10995331Samw 11005331Samw *cookiep = (uint32_t)next_cookie; 11015331Samw break; 11025331Samw } 11035331Samw 11045331Samw if (ebuf) 11055331Samw kmem_free(ebuf, ebufsize); 11065331Samw 11075331Samw return (error); 11085331Samw } 11095331Samw 11105331Samw /* 11115331Samw * smb_sa_to_va_mask 11125331Samw * 11135331Samw * Set va_mask by running through the SMB_AT_* #define's and 11145331Samw * setting those bits that correspond to the SMB_AT_* bits 11155331Samw * set in sa_mask. 11165331Samw */ 11175331Samw 11185331Samw void 11195331Samw smb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp) 11205331Samw { 11215331Samw int i; 11225331Samw uint_t smask; 11235331Samw 11245331Samw smask = (sa_mask); 11255331Samw for (i = SMB_AT_TYPE; (i < SMB_AT_MAX) && (smask != 0); ++i) { 11265331Samw if (smask & 1) 11275331Samw *(va_maskp) |= smb_attrmap[i]; 11285331Samw 11295331Samw smask >>= 1; 11305331Samw } 11315331Samw } 11325331Samw 11335331Samw /* 11345331Samw * smb_vop_getdents() 11355331Samw * 11365331Samw * Upon success, the smb_node corresponding to each entry returned will 11375331Samw * have a reference taken on it. These will be released in 11385331Samw * smb_trans2_find_get_dents(). 11395331Samw * 11405331Samw * If an error is returned from this routine, a list of already processed 11415331Samw * entries will be returned. The smb_nodes corresponding to these entries 11425331Samw * will be referenced, and will be released in smb_trans2_find_get_dents(). 11435331Samw * 11445331Samw * The returned dp->d_name field will contain either the on-disk name or, if 11455331Samw * it needs mangling or has a case-insensitive collision, the mangled 11465331Samw * "shortname." In this case, the on-disk name can be retrieved from the 11475331Samw * smb_node's od_name (the smb_node is passed to smb_gather_dents_info()). 11485331Samw */ 11495331Samw 11505331Samw int /*ARGSUSED*/ 11515331Samw smb_vop_getdents( 11525331Samw smb_node_t *dir_snode, 11535331Samw uint32_t *cookiep, 11545331Samw uint64_t *verifierp, 11555331Samw int32_t *dircountp, 11565331Samw char *arg, 11575331Samw char *pattern, 11585331Samw uint32_t flags, 11595331Samw smb_request_t *sr, 11605772Sas200622 cred_t *cr) 11615331Samw { 11625331Samw int error = 0; 11635331Samw int maxentries; 11645331Samw int num_bytes; 11655331Samw int resid; 11665331Samw char *dirbuf = NULL; 11675331Samw vnode_t *dvp; 11685331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 11695331Samw smb_dent_info_hdr_t *ihdr = (smb_dent_info_hdr_t *)arg; 11705331Samw 11715331Samw dvp = dir_snode->vp; 11725331Samw 11735331Samw resid = ihdr->uio.uio_resid; 11745331Samw maxentries = resid / SMB_MAX_DENT_INFO_SIZE; 11755331Samw 11765331Samw bzero(ihdr->iov->iov_base, resid); 11775331Samw 11785331Samw dirbuf = kmem_alloc(SMB_MINLEN_RDDIR_BUF, KM_SLEEP); 11795331Samw 11805331Samw while (maxentries) { 11815331Samw 11825331Samw bzero(dirbuf, SMB_MINLEN_RDDIR_BUF); 11835331Samw 11845331Samw num_bytes = SMB_MINLEN_RDDIR_BUF; 11855331Samw error = smb_vop_readdir_readpage(dvp, dirbuf, *cookiep, 11865772Sas200622 &num_bytes, cr, flags); 11875331Samw 11885331Samw if (error || (num_bytes <= 0)) 11895331Samw break; 11905331Samw 11915331Samw error = smb_vop_getdents_entries(dir_snode, cookiep, dircountp, 11925772Sas200622 arg, flags, sr, cr, dirbuf, &maxentries, num_bytes, 11935331Samw pattern); 11945331Samw 11955331Samw if (error) 11965331Samw goto out; 11975331Samw } 11985331Samw 11995331Samw if (num_bytes < 0) { 12005331Samw error = -1; 12015331Samw } else if (num_bytes == 0) { 12025331Samw *cookiep = SMB_EOF; 12035331Samw error = 0; 12045331Samw } else { 12055331Samw error = 0; 12065331Samw } 12075331Samw 12085331Samw out: 12095331Samw if (dirbuf) 12105331Samw kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 12115331Samw 12125331Samw return (error); 12135331Samw } 12145331Samw 12155331Samw /* 12165331Samw * smb_vop_getdents_entries() 12175331Samw * 12185331Samw * This function retrieves names from the SMB_MINLEN_RDDIR_BUF-sized buffer 12195331Samw * returned by smb_vop_readdir_readpage() to smb_vop_getdents(). 12205331Samw * 12215331Samw * Both dirent64_t and edirent_t structures need to be handled. The former is 12225331Samw * needed for file systems that do not support VFSFT_DIRENTFLAGS. The latter 12235331Samw * is required for properly handling case collisions on file systems that 12245331Samw * support case-insensitivity. edirent_t is also used on case-sensitive 12255331Samw * file systems where VFSFT_DIRENTFLAGS is available. 12265331Samw */ 12275331Samw 12285331Samw static int 12295331Samw smb_vop_getdents_entries( 12305331Samw smb_node_t *dir_snode, 12315331Samw uint32_t *cookiep, 12325331Samw int32_t *dircountp, 12335331Samw char *arg, 12345331Samw uint32_t flags, 1235*6139Sjb150015 smb_request_t *sr, 12365331Samw cred_t *cr, 12375331Samw char *dirbuf, 12385331Samw int *maxentries, 12395331Samw int num_bytes, 12405331Samw char *pattern) 12415331Samw { 12425331Samw uint32_t next_cookie; 12435331Samw int ebufsize; 12445331Samw char *tmp_name; 12455331Samw int error; 12465331Samw int rc; 12475331Samw char shortname[MANGLE_NAMELEN]; 12485331Samw char name83[MANGLE_NAMELEN]; 12495331Samw char *ebuf = NULL; 12505331Samw dirent64_t *dp = NULL; 12515331Samw edirent_t *edp; 12525331Samw smb_node_t *ret_snode; 12535331Samw smb_attr_t ret_attr; 12545331Samw vnode_t *dvp; 12555331Samw vnode_t *fvp; 12565331Samw 12575331Samw ASSERT(dirbuf); 12585331Samw 12595331Samw dvp = dir_snode->vp; 12605331Samw 12615331Samw if (vfs_has_feature(dvp->v_vfsp, VFSFT_DIRENTFLAGS)) { 12625331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 12635331Samw edp = (edirent_t *)dirbuf; 12645331Samw } else { 12655331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 12665331Samw dp = (dirent64_t *)dirbuf; 12675331Samw ebufsize = EDIRENT_RECLEN(MAXNAMELEN); 12685331Samw ebuf = kmem_zalloc(ebufsize, KM_SLEEP); 12695331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 12705331Samw edp = (edirent_t *)ebuf; 12715331Samw } 12725331Samw 12735331Samw while (edp) { 12745331Samw if (dp) 12755331Samw DP_TO_EDP(dp, edp); 12765331Samw 12775331Samw if (*maxentries == 0) 12785331Samw break; 12795331Samw 12805331Samw next_cookie = (uint32_t)edp->ed_off; 12815331Samw 12825331Samw if (edp->ed_ino == 0) { 12835331Samw *cookiep = next_cookie; 12845331Samw if (dp) { 12855331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 12865331Samw DP_ADVANCE(dp, dirbuf, num_bytes); 12875331Samw if (dp == NULL) 12885331Samw edp = NULL; 12895331Samw } else { 12905331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 12915331Samw EDP_ADVANCE(edp, dirbuf, num_bytes); 12925331Samw } 12935331Samw continue; 12945331Samw } 12955331Samw 12965331Samw error = smb_vop_lookup(dvp, edp->ed_name, &fvp, 12975772Sas200622 NULL, 0, NULL, cr); 12985331Samw 12995331Samw if (error) { 13005331Samw if (error == ENOENT) { 13015331Samw *cookiep = next_cookie; 13025331Samw if (dp) { 13035331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 13045331Samw DP_ADVANCE(dp, dirbuf, 13055331Samw num_bytes); 13065331Samw if (dp == NULL) 13075331Samw edp = NULL; 13085331Samw } else { 13095331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 13105331Samw EDP_ADVANCE(edp, dirbuf, 13115331Samw num_bytes); 13125331Samw } 13135331Samw continue; 13145331Samw } 13155331Samw if (ebuf) 13165331Samw kmem_free(ebuf, ebufsize); 13175331Samw 13185331Samw return (error); 13195331Samw } 13205331Samw 13215331Samw ret_snode = smb_node_lookup(sr, NULL, cr, fvp, 13225331Samw edp->ed_name, dir_snode, NULL, &ret_attr); 13235331Samw 13245331Samw if (ret_snode == NULL) { 13255331Samw VN_RELE(fvp); 13265331Samw 13275331Samw if (ebuf) 13285331Samw kmem_free(ebuf, ebufsize); 13295331Samw 13305331Samw return (ENOMEM); 13315331Samw } 13325331Samw 13335331Samw if (smb_match_name(edp->ed_ino, edp->ed_name, shortname, 13345331Samw name83, pattern, (flags & SMB_IGNORE_CASE))) { 13355331Samw 13365331Samw tmp_name = edp->ed_name; 13375331Samw 13385331Samw if ((flags & SMB_IGNORE_CASE) && 13395331Samw ED_CASE_CONFLICTS(edp)) { 13405331Samw rc = smb_mangle_name(edp->ed_ino, edp->ed_name, 13415331Samw shortname, name83, 1); 13425331Samw if (rc == 1) 13435331Samw tmp_name = shortname; 13445331Samw } else { 13455331Samw rc = smb_mangle_name(edp->ed_ino, edp->ed_name, 13465331Samw shortname, name83, 0); 13475331Samw } 13485331Samw 13495331Samw if (rc != 1) { 13505331Samw (void) strlcpy(shortname, edp->ed_name, 13515331Samw MANGLE_NAMELEN); 13525331Samw (void) strlcpy(name83, edp->ed_name, 13535331Samw MANGLE_NAMELEN); 13545331Samw shortname[MANGLE_NAMELEN - 1] = '\0'; 13555331Samw name83[MANGLE_NAMELEN - 1] = '\0'; 13565331Samw } 13575331Samw 13585331Samw error = smb_gather_dents_info(arg, edp->ed_ino, 13595331Samw strlen(tmp_name), tmp_name, next_cookie, dircountp, 13605331Samw &ret_attr, ret_snode, shortname, name83); 13615331Samw 13625331Samw if (error > 0) { 13635331Samw if (ebuf) 13645331Samw kmem_free(ebuf, ebufsize); 13655331Samw return (error); 13665331Samw } 13675331Samw 13685331Samw /* 13695331Samw * Treat errors from smb_gather_dents_info() that are 13705331Samw * < 0 the same as EOF. 13715331Samw */ 13725331Samw if (error < 0) { 13735331Samw if (ebuf) 13745331Samw kmem_free(ebuf, ebufsize); 13755331Samw *maxentries = 0; 13765331Samw return (0); 13775331Samw } 13785331Samw (*maxentries)--; 13795331Samw } else { 13805331Samw smb_node_release(ret_snode); 13815331Samw } 13825331Samw 13835331Samw *cookiep = next_cookie; 13845331Samw 13855331Samw if (dp) { 13865331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 13875331Samw DP_ADVANCE(dp, dirbuf, num_bytes); 13885331Samw if (dp == NULL) 13895331Samw edp = NULL; 13905331Samw } else { 13915331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 13925331Samw EDP_ADVANCE(edp, dirbuf, num_bytes); 13935331Samw } 13945331Samw } 13955331Samw 13965331Samw if (ebuf) 13975331Samw kmem_free(ebuf, ebufsize); 13985331Samw 13995331Samw return (0); 14005331Samw } 14015331Samw 14025331Samw /* 14035331Samw * smb_vop_stream_lookup() 14045331Samw * 14055331Samw * The name returned in od_name is the on-disk name of the stream with the 14065331Samw * SMB_STREAM_PREFIX stripped off. od_name should be allocated to MAXNAMELEN 14075331Samw * by the caller. 14085331Samw */ 14095331Samw 14105331Samw int 1411*6139Sjb150015 smb_vop_stream_lookup( 1412*6139Sjb150015 vnode_t *fvp, 1413*6139Sjb150015 char *stream_name, 1414*6139Sjb150015 vnode_t **vpp, 1415*6139Sjb150015 char *od_name, 1416*6139Sjb150015 vnode_t **xattrdirvpp, 1417*6139Sjb150015 int flags, 1418*6139Sjb150015 vnode_t *rootvp, 1419*6139Sjb150015 cred_t *cr) 14205331Samw { 14215331Samw char *solaris_stream_name; 14225331Samw char *name; 14235331Samw int error; 14245331Samw 14255331Samw if ((error = smb_vop_lookup_xattrdir(fvp, xattrdirvpp, 14265772Sas200622 LOOKUP_XATTR | CREATE_XATTR_DIR, cr)) != 0) 14275331Samw return (error); 14285331Samw 14295331Samw /* 14305331Samw * Prepend SMB_STREAM_PREFIX to stream name 14315331Samw */ 14325331Samw 14335331Samw solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 14345331Samw (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX, 14355331Samw stream_name); 14365331Samw 14375331Samw /* 14385331Samw * "name" will hold the on-disk name returned from smb_vop_lookup 14395331Samw * for the stream, including the SMB_STREAM_PREFIX. 14405331Samw */ 14415331Samw 14425331Samw name = kmem_zalloc(MAXNAMELEN, KM_SLEEP); 14435331Samw 14445331Samw if ((error = smb_vop_lookup(*xattrdirvpp, solaris_stream_name, vpp, 14455772Sas200622 name, flags, rootvp, cr)) != 0) { 14465331Samw VN_RELE(*xattrdirvpp); 14475331Samw } else { 14485331Samw (void) strlcpy(od_name, &(name[SMB_STREAM_PREFIX_LEN]), 14495331Samw MAXNAMELEN); 14505331Samw } 14515331Samw 14525331Samw kmem_free(solaris_stream_name, MAXNAMELEN); 14535331Samw kmem_free(name, MAXNAMELEN); 14545331Samw 14555331Samw return (error); 14565331Samw } 14575331Samw 14585331Samw int 14595331Samw smb_vop_stream_create(vnode_t *fvp, char *stream_name, smb_attr_t *attr, 14605772Sas200622 vnode_t **vpp, vnode_t **xattrdirvpp, int flags, cred_t *cr) 14615331Samw { 14625331Samw char *solaris_stream_name; 14635331Samw int error; 14645331Samw 14655331Samw if ((error = smb_vop_lookup_xattrdir(fvp, xattrdirvpp, 14665772Sas200622 LOOKUP_XATTR | CREATE_XATTR_DIR, cr)) != 0) 14675331Samw return (error); 14685331Samw 14695331Samw /* 14705331Samw * Prepend SMB_STREAM_PREFIX to stream name 14715331Samw */ 14725331Samw 14735331Samw solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 14745331Samw (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX, 14755331Samw stream_name); 14765331Samw 14775331Samw if ((error = smb_vop_create(*xattrdirvpp, solaris_stream_name, attr, 14785772Sas200622 vpp, flags, cr, NULL)) != 0) 14795331Samw VN_RELE(*xattrdirvpp); 14805331Samw 14815331Samw kmem_free(solaris_stream_name, MAXNAMELEN); 14825331Samw 14835331Samw return (error); 14845331Samw } 14855331Samw 14865331Samw int 14875772Sas200622 smb_vop_stream_remove(vnode_t *vp, char *stream_name, int flags, cred_t *cr) 14885331Samw { 14895331Samw char *solaris_stream_name; 14905331Samw vnode_t *xattrdirvp; 14915331Samw int error; 14925331Samw 1493*6139Sjb150015 error = smb_vop_lookup_xattrdir(vp, &xattrdirvp, LOOKUP_XATTR, cr); 1494*6139Sjb150015 if (error != 0) 14955331Samw return (error); 14965331Samw 14975331Samw /* 14985331Samw * Prepend SMB_STREAM_PREFIX to stream name 14995331Samw */ 15005331Samw 15015331Samw solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 15025331Samw (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX, 15035331Samw stream_name); 15045331Samw 15055331Samw /* XXX might have to use kcred */ 15065772Sas200622 error = smb_vop_remove(xattrdirvp, solaris_stream_name, flags, cr); 15075331Samw 15085331Samw kmem_free(solaris_stream_name, MAXNAMELEN); 15095331Samw 15105331Samw return (error); 15115331Samw } 15125331Samw 15135331Samw /* 15145331Samw * smb_vop_stream_readdir() 15155331Samw * 15165331Samw * Note: stream_info.size is not filled in in this routine. 15175331Samw * It needs to be filled in by the caller due to the parameters for getattr. 15185331Samw * 15195331Samw * stream_info.name is set to the on-disk stream name with the SMB_STREAM_PREFIX 15205331Samw * removed. 15215331Samw */ 15225331Samw 15235331Samw int 15245331Samw smb_vop_stream_readdir(vnode_t *fvp, uint32_t *cookiep, 15255331Samw struct fs_stream_info *stream_info, vnode_t **vpp, vnode_t **xattrdirvpp, 15265772Sas200622 int flags, cred_t *cr) 15275331Samw { 15285331Samw int nsize = MAXNAMELEN-1; 15295331Samw int error = 0; 15305331Samw ino64_t ino; 15315331Samw char *tmp_name; 15325331Samw vnode_t *xattrdirvp; 15335331Samw vnode_t *vp; 15345331Samw 15355331Samw if ((error = smb_vop_lookup_xattrdir(fvp, &xattrdirvp, LOOKUP_XATTR, 15365772Sas200622 cr)) != 0) 15375331Samw return (error); 15385331Samw 15395331Samw bzero(stream_info->name, sizeof (stream_info->name)); 15405331Samw stream_info->size = 0; 15415331Samw 15425331Samw tmp_name = kmem_zalloc(MAXNAMELEN, KM_SLEEP); 15435331Samw 15445331Samw for (;;) { 15455331Samw error = smb_vop_readdir(xattrdirvp, cookiep, tmp_name, &nsize, 15465772Sas200622 &ino, &vp, NULL, flags | SMB_STREAM_RDDIR, cr); 15475331Samw 15485331Samw if (error || (*cookiep == SMB_EOF)) 15495331Samw break; 15505331Samw 15515331Samw if (strncmp(tmp_name, SMB_STREAM_PREFIX, 15525331Samw SMB_STREAM_PREFIX_LEN)) { 15535331Samw VN_RELE(vp); 15545331Samw continue; 15555331Samw } 15565331Samw 15575331Samw tmp_name[nsize] = '\0'; 15585331Samw (void) strlcpy(stream_info->name, 15595331Samw &(tmp_name[SMB_STREAM_PREFIX_LEN]), 15605331Samw sizeof (stream_info->name)); 15615331Samw 15625331Samw nsize -= SMB_STREAM_PREFIX_LEN; 15635331Samw break; 15645331Samw } 15655331Samw 15665331Samw if ((error == 0) && nsize) { 15675331Samw if (vpp) 15685331Samw *vpp = vp; 15695331Samw else 15705331Samw VN_RELE(vp); 15715331Samw 15725331Samw if (xattrdirvpp) 15735331Samw *xattrdirvpp = xattrdirvp; 15745331Samw else 15755331Samw VN_RELE(xattrdirvp); 15765331Samw 15775781Sjc198820 } else { 15785781Sjc198820 VN_RELE(xattrdirvp); 15795331Samw } 15805331Samw 15815331Samw kmem_free(tmp_name, MAXNAMELEN); 15825331Samw 15835331Samw return (error); 15845331Samw } 15855331Samw 15865331Samw int 15875331Samw smb_vop_lookup_xattrdir(vnode_t *fvp, vnode_t **xattrdirvpp, int flags, 15885772Sas200622 cred_t *cr) 15895331Samw { 15905331Samw int error; 15915331Samw 15925772Sas200622 error = VOP_LOOKUP(fvp, "", xattrdirvpp, NULL, flags, NULL, cr, 15935772Sas200622 &smb_ct, NULL, NULL); 15945331Samw return (error); 15955331Samw } 15965331Samw 15975331Samw /* 15985331Samw * smb_vop_traverse_check() 15995331Samw * 16005331Samw * This function checks to see if the passed-in vnode has a file system 16015331Samw * mounted on it. If it does, the mount point is "traversed" and the 16025331Samw * vnode for the root of the file system is returned. 16035331Samw */ 16045331Samw 16055331Samw int 16065331Samw smb_vop_traverse_check(vnode_t **vpp) 16075331Samw { 16085331Samw int error; 16095331Samw 16105331Samw if (vn_mountedvfs(*vpp) == 0) 16115331Samw return (0); 16125331Samw 16135331Samw /* 16145331Samw * traverse() may return a different held vnode, even in the error case. 16155331Samw * If it returns a different vnode, it will have released the original. 16165331Samw */ 16175331Samw 16185331Samw error = traverse(vpp); 16195331Samw 16205331Samw return (error); 16215331Samw } 16225331Samw 16235331Samw int /*ARGSUSED*/ 16245331Samw smb_vop_statfs(vnode_t *vp, struct statvfs64 *statp, cred_t *cr) 16255331Samw { 16265331Samw int error; 16275331Samw 16285331Samw error = VFS_STATVFS(vp->v_vfsp, statp); 16295331Samw 16305331Samw return (error); 16315331Samw } 16325331Samw 16335331Samw /* 16345331Samw * smb_vop_acl_read 16355331Samw * 16365331Samw * Reads the ACL of the specified file into 'aclp'. 16375331Samw * acl_type is the type of ACL which the filesystem supports. 16385331Samw * 16395331Samw * Caller has to free the allocated memory for aclp by calling 16405331Samw * acl_free(). 16415331Samw */ 16425331Samw int 16435331Samw smb_vop_acl_read(vnode_t *vp, acl_t **aclp, int flags, acl_type_t acl_type, 16445772Sas200622 cred_t *cr) 16455331Samw { 16465331Samw int error; 16475331Samw vsecattr_t vsecattr; 16485331Samw 16495331Samw ASSERT(vp); 16505331Samw ASSERT(aclp); 16515331Samw 16525331Samw *aclp = NULL; 16535331Samw bzero(&vsecattr, sizeof (vsecattr_t)); 16545331Samw 16555331Samw switch (acl_type) { 16565331Samw case ACLENT_T: 16575331Samw vsecattr.vsa_mask = VSA_ACL | VSA_ACLCNT | VSA_DFACL | 16585331Samw VSA_DFACLCNT; 16595331Samw break; 16605331Samw 16615331Samw case ACE_T: 16625331Samw vsecattr.vsa_mask = VSA_ACE | VSA_ACECNT | VSA_ACE_ACLFLAGS; 16635331Samw break; 16645331Samw 16655331Samw default: 16665331Samw return (EINVAL); 16675331Samw } 16685331Samw 16695772Sas200622 if (error = VOP_GETSECATTR(vp, &vsecattr, flags, cr, &smb_ct)) 16705331Samw return (error); 16715331Samw 16725521Sas200622 *aclp = smb_fsacl_from_vsa(&vsecattr, acl_type); 16735331Samw if (vp->v_type == VDIR) 16745331Samw (*aclp)->acl_flags |= ACL_IS_DIR; 16755331Samw 16765331Samw return (0); 16775331Samw } 16785331Samw 16795331Samw /* 16805331Samw * smb_vop_acl_write 16815331Samw * 16825331Samw * Writes the given ACL in aclp for the specified file. 16835331Samw */ 16845331Samw int 16855772Sas200622 smb_vop_acl_write(vnode_t *vp, acl_t *aclp, int flags, cred_t *cr) 16865331Samw { 16875331Samw int error; 16885331Samw vsecattr_t vsecattr; 16895331Samw int aclbsize; 16905331Samw 16915331Samw ASSERT(vp); 16925331Samw ASSERT(aclp); 16935331Samw 16945521Sas200622 error = smb_fsacl_to_vsa(aclp, &vsecattr, &aclbsize); 16955331Samw 16965331Samw if (error == 0) { 16975331Samw (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); 16985772Sas200622 error = VOP_SETSECATTR(vp, &vsecattr, flags, cr, &smb_ct); 16995331Samw VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 17005331Samw } 17015331Samw 17025331Samw if (aclbsize && vsecattr.vsa_aclentp) 17035331Samw kmem_free(vsecattr.vsa_aclentp, aclbsize); 17045331Samw 17055331Samw return (error); 17065331Samw } 17075331Samw 17085331Samw /* 17095331Samw * smb_vop_acl_type 17105331Samw * 17115331Samw * Determines the ACL type for the given vnode. 17125331Samw * ACLENT_T is a Posix ACL and ACE_T is a ZFS ACL. 17135331Samw */ 17145331Samw acl_type_t 17155331Samw smb_vop_acl_type(vnode_t *vp) 17165331Samw { 17175331Samw int error; 17185331Samw ulong_t whichacl; 17195331Samw 17205331Samw error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &whichacl, kcred, NULL); 17215331Samw if (error != 0) { 17225331Samw /* 17235331Samw * If we got an error, then the filesystem 17245331Samw * likely does not understand the _PC_ACL_ENABLED 17255331Samw * pathconf. In this case, we fall back to trying 17265331Samw * POSIX-draft (aka UFS-style) ACLs. 17275331Samw */ 17285331Samw whichacl = _ACL_ACLENT_ENABLED; 17295331Samw } 17305331Samw 17315331Samw if (!(whichacl & (_ACL_ACE_ENABLED | _ACL_ACLENT_ENABLED))) { 17325331Samw /* 17335331Samw * If the file system supports neither ACE nor 17345331Samw * ACLENT ACLs we will fall back to UFS-style ACLs 17355331Samw * like we did above if there was an error upon 17365331Samw * calling VOP_PATHCONF. 17375331Samw * 17385331Samw * ACE and ACLENT type ACLs are the only interfaces 17395331Samw * supported thus far. If any other bits are set on 17405331Samw * 'whichacl' upon return from VOP_PATHCONF, we will 17415331Samw * ignore them. 17425331Samw */ 17435331Samw whichacl = _ACL_ACLENT_ENABLED; 17445331Samw } 17455331Samw 17465331Samw if (whichacl == _ACL_ACLENT_ENABLED) 17475331Samw return (ACLENT_T); 17485331Samw 17495331Samw return (ACE_T); 17505331Samw } 17515331Samw 17525331Samw static int zfs_perms[] = { 17535331Samw ACE_READ_DATA, ACE_WRITE_DATA, ACE_APPEND_DATA, ACE_READ_NAMED_ATTRS, 17545331Samw ACE_WRITE_NAMED_ATTRS, ACE_EXECUTE, ACE_DELETE_CHILD, 17555331Samw ACE_READ_ATTRIBUTES, ACE_WRITE_ATTRIBUTES, ACE_DELETE, ACE_READ_ACL, 17565331Samw ACE_WRITE_ACL, ACE_WRITE_OWNER, ACE_SYNCHRONIZE 17575331Samw }; 17585331Samw 17595331Samw static int unix_perms[] = { VREAD, VWRITE, VEXEC }; 17605331Samw /* 17615331Samw * smb_vop_eaccess 17625331Samw * 17635331Samw * Returns the effective permission of the given credential for the 17645331Samw * specified object. 17655331Samw * 17665331Samw * This is just a workaround. We need VFS/FS support for this. 17675331Samw */ 17685331Samw void 17695331Samw smb_vop_eaccess(vnode_t *vp, int *mode, int flags, vnode_t *dir_vp, cred_t *cr) 17705331Samw { 17715331Samw int error, i; 17725331Samw int pnum; 17735331Samw 17745331Samw *mode = 0; 17755331Samw 17765331Samw if (flags == V_ACE_MASK) { 17775331Samw pnum = sizeof (zfs_perms) / sizeof (int); 17785331Samw 17795331Samw for (i = 0; i < pnum; i++) { 17805331Samw error = smb_vop_access(vp, zfs_perms[i], flags, 17815331Samw dir_vp, cr); 17825331Samw if (error == 0) 17835331Samw *mode |= zfs_perms[i]; 17845331Samw } 17855331Samw } else { 17865331Samw pnum = sizeof (unix_perms) / sizeof (int); 17875331Samw 17885331Samw for (i = 0; i < pnum; i++) { 17895331Samw error = smb_vop_access(vp, unix_perms[i], flags, 17905331Samw dir_vp, cr); 17915331Samw if (error == 0) 17925331Samw *mode |= unix_perms[i]; 17935331Samw } 17945331Samw } 17955331Samw } 17965772Sas200622 17975772Sas200622 /* 17985772Sas200622 * smb_vop_shrlock() 17995772Sas200622 * 18005772Sas200622 * See comments for smb_fsop_shrlock() 18015772Sas200622 */ 18025772Sas200622 18035772Sas200622 int 18045772Sas200622 smb_vop_shrlock(vnode_t *vp, uint32_t uniq_fid, uint32_t desired_access, 18055772Sas200622 uint32_t share_access, cred_t *cr) 18065772Sas200622 { 18075772Sas200622 struct shrlock shr; 18085772Sas200622 struct shr_locowner shr_own; 18095772Sas200622 short new_access = 0; 18105772Sas200622 short deny = 0; 18115772Sas200622 int flag = 0; 18125772Sas200622 int cmd; 18135772Sas200622 18145772Sas200622 cmd = (nbl_need_check(vp)) ? F_SHARE_NBMAND : F_SHARE; 18155772Sas200622 18165772Sas200622 /* 18175772Sas200622 * Check if this is a metadata access 18185772Sas200622 */ 18195772Sas200622 18205772Sas200622 if ((desired_access & FILE_DATA_ALL) == 0) { 18215772Sas200622 new_access |= F_MDACC; 18225772Sas200622 } else { 18235772Sas200622 if (desired_access & (ACE_READ_DATA | ACE_EXECUTE)) { 18245772Sas200622 new_access |= F_RDACC; 18255772Sas200622 flag |= FREAD; 18265772Sas200622 } 18275772Sas200622 18285772Sas200622 if (desired_access & (ACE_WRITE_DATA | ACE_APPEND_DATA | 18295772Sas200622 ACE_ADD_FILE)) { 18305772Sas200622 new_access |= F_WRACC; 18315772Sas200622 flag |= FWRITE; 18325772Sas200622 } 18335772Sas200622 18345772Sas200622 if (SMB_DENY_READ(share_access)) { 18355772Sas200622 deny |= F_RDDNY; 18365772Sas200622 } 18375772Sas200622 18385772Sas200622 if (SMB_DENY_WRITE(share_access)) { 18395772Sas200622 deny |= F_WRDNY; 18405772Sas200622 } 18415772Sas200622 18425772Sas200622 if (cmd == F_SHARE_NBMAND) { 18435772Sas200622 if (desired_access & ACE_DELETE) 18445772Sas200622 new_access |= F_RMACC; 18455772Sas200622 18465772Sas200622 if (SMB_DENY_DELETE(share_access)) { 18475772Sas200622 deny |= F_RMDNY; 18485772Sas200622 } 18495772Sas200622 } 18505772Sas200622 } 18515772Sas200622 18525772Sas200622 shr.s_access = new_access; 18535772Sas200622 shr.s_deny = deny; 18545772Sas200622 shr.s_sysid = smb_ct.cc_sysid; 18555772Sas200622 shr.s_pid = uniq_fid; 18565772Sas200622 shr.s_own_len = sizeof (shr_own); 18575772Sas200622 shr.s_owner = (caddr_t)&shr_own; 18585772Sas200622 shr_own.sl_id = shr.s_sysid; 18595772Sas200622 shr_own.sl_pid = shr.s_pid; 18605772Sas200622 18615772Sas200622 return (VOP_SHRLOCK(vp, cmd, &shr, flag, cr, NULL)); 18625772Sas200622 } 18635772Sas200622 18645772Sas200622 int 18655772Sas200622 smb_vop_unshrlock(vnode_t *vp, uint32_t uniq_fid, cred_t *cr) 18665772Sas200622 { 18675772Sas200622 struct shrlock shr; 18685772Sas200622 struct shr_locowner shr_own; 18695772Sas200622 18705772Sas200622 /* 18715772Sas200622 * For s_access and s_deny, we do not need to pass in the original 18725772Sas200622 * values. 18735772Sas200622 */ 18745772Sas200622 18755772Sas200622 shr.s_access = 0; 18765772Sas200622 shr.s_deny = 0; 18775772Sas200622 shr.s_sysid = smb_ct.cc_sysid; 18785772Sas200622 shr.s_pid = uniq_fid; 18795772Sas200622 shr.s_own_len = sizeof (shr_own); 18805772Sas200622 shr.s_owner = (caddr_t)&shr_own; 18815772Sas200622 shr_own.sl_id = shr.s_sysid; 18825772Sas200622 shr_own.sl_pid = shr.s_pid; 18835772Sas200622 18845772Sas200622 return (VOP_SHRLOCK(vp, F_UNSHARE, &shr, 0, cr, NULL)); 18855772Sas200622 } 1886