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> 405521Sas200622 415331Samw #include <smbsrv/smb_vops.h> 425331Samw #include <smbsrv/string.h> 435521Sas200622 445331Samw #include <smbsrv/smbtrans.h> 455521Sas200622 #include <smbsrv/smb_fsops.h> 465521Sas200622 #include <smbsrv/smb_kproto.h> 475331Samw #include <smbsrv/smb_incl.h> 485521Sas200622 495772Sas200622 void 505772Sas200622 smb_vop_setup_xvattr(smb_attr_t *smb_attr, xvattr_t *xvattr); 515331Samw 525331Samw static int 535331Samw smb_vop_readdir_readpage(vnode_t *vp, void *buf, uint32_t offset, int *count, 545772Sas200622 cred_t *cr, int flags); 555331Samw 565331Samw static int 575331Samw smb_vop_readdir_entry(vnode_t *dvp, uint32_t *cookiep, char *name, int *namelen, 585331Samw ino64_t *inop, vnode_t **vpp, char *od_name, int flags, cred_t *cr, 595772Sas200622 char *dirbuf, int num_bytes); 605331Samw 615331Samw static int 625331Samw smb_vop_getdents_entries(smb_node_t *dir_snode, uint32_t *cookiep, 635331Samw int32_t *dircountp, char *arg, uint32_t flags, struct smb_request *sr, 645772Sas200622 cred_t *cr, char *dirbuf, int *maxentries, int num_bytes, char *); 655331Samw 665331Samw extern int 675331Samw smb_gather_dents_info(char *args, ino_t fileid, int namelen, 685331Samw char *name, uint32_t cookie, int32_t *countp, 695331Samw smb_attr_t *attr, struct smb_node *snode, 705331Samw char *shortname, char *name83); 715331Samw 725331Samw static void 735331Samw smb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp); 745331Samw 755772Sas200622 extern sysid_t lm_alloc_sysidt(); 765772Sas200622 775331Samw #define SMB_AT_MAX 16 785331Samw static uint_t smb_attrmap[SMB_AT_MAX] = { 795331Samw 0, 805331Samw AT_TYPE, 815331Samw AT_MODE, 825331Samw AT_UID, 835331Samw AT_GID, 845331Samw AT_FSID, 855331Samw AT_NODEID, 865331Samw AT_NLINK, 875331Samw AT_SIZE, 885331Samw AT_ATIME, 895331Samw AT_MTIME, 905331Samw AT_CTIME, 915331Samw AT_RDEV, 925331Samw AT_BLKSIZE, 935331Samw AT_NBLOCKS, 945331Samw AT_SEQ 955331Samw }; 965331Samw 975772Sas200622 /* 985772Sas200622 * The smb_ct will be used primarily for range locking. 995772Sas200622 * Since the CIFS server is mapping its locks to POSIX locks, 1005772Sas200622 * only one pid is used for operations originating from the 1015772Sas200622 * CIFS server (to represent CIFS in the VOP_FRLOCK routines). 1025772Sas200622 */ 1035772Sas200622 1045772Sas200622 caller_context_t smb_ct; 1055772Sas200622 1065772Sas200622 /* 1075772Sas200622 * smb_vop_start() 1085772Sas200622 * 1095772Sas200622 * Initialize the smb caller context. This function must be called 1105772Sas200622 * before any other smb_vop calls. 1115772Sas200622 */ 1125772Sas200622 1135772Sas200622 void 1145772Sas200622 smb_vop_start(void) 1155331Samw { 1165772Sas200622 static boolean_t initialized = B_FALSE; 1175772Sas200622 1185772Sas200622 if (!initialized) { 1195772Sas200622 smb_ct.cc_caller_id = fs_new_caller_id(); 1205772Sas200622 smb_ct.cc_pid = ttoproc(curthread)->p_pid; 1215772Sas200622 smb_ct.cc_sysid = lm_alloc_sysidt(); 1225772Sas200622 initialized = B_TRUE; 1235772Sas200622 } 1245331Samw } 1255331Samw 1265331Samw int 1275772Sas200622 smb_vop_open(vnode_t **vpp, int mode, cred_t *cred) 1285331Samw { 1295772Sas200622 return (VOP_OPEN(vpp, mode, cred, &smb_ct)); 1305772Sas200622 } 1315772Sas200622 1325772Sas200622 int 1335772Sas200622 smb_vop_close(vnode_t *vp, int mode, cred_t *cred) 1345772Sas200622 { 1355772Sas200622 return (VOP_CLOSE(vp, mode, 1, (offset_t)0, cred, &smb_ct)); 1365331Samw } 1375331Samw 1385331Samw /* 1395331Samw * The smb_vop_* functions have minimal knowledge of CIFS semantics and 1405331Samw * serve as an interface to the VFS layer. 1415331Samw * 1425331Samw * Only smb_fsop_* layer functions should call smb_vop_* layer functions. 1435331Samw * (Higher-level CIFS service code should never skip the smb_fsop_* layer 1445331Samw * to call smb_vop_* layer functions directly.) 1455331Samw */ 1465331Samw 1475331Samw /* 1485331Samw * XXX - Extended attributes support in the file system assumed. 1495331Samw * This is needed for full NT Streams functionality. 1505331Samw */ 1515331Samw 1525331Samw int 1535772Sas200622 smb_vop_read(vnode_t *vp, uio_t *uiop, cred_t *cr) 1545331Samw { 1555331Samw int error; 1565331Samw 1575331Samw (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL); 1585772Sas200622 error = VOP_READ(vp, uiop, 0, cr, &smb_ct); 1595331Samw VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 1605331Samw return (error); 1615331Samw } 1625331Samw 1635331Samw int 1645331Samw smb_vop_write(vnode_t *vp, uio_t *uiop, uint32_t *flag, uint32_t *lcount, 1655772Sas200622 cred_t *cr) 1665331Samw { 1675331Samw int error; 1685331Samw int ioflag = 0; 1695331Samw 1705331Samw *lcount = uiop->uio_resid; 1715331Samw 1725331Samw if (*flag == FSSTAB_FILE_SYNC) 1735331Samw ioflag = FSYNC; 1745331Samw 1755331Samw uiop->uio_llimit = MAXOFFSET_T; 1765331Samw 1775331Samw (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); 1785772Sas200622 error = VOP_WRITE(vp, uiop, ioflag, cr, &smb_ct); 1795331Samw VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 1805331Samw 1815331Samw *lcount -= uiop->uio_resid; 1825331Samw 1835331Samw return (error); 1845331Samw } 1855331Samw 1865331Samw /* 1875331Samw * smb_vop_getattr() 1885331Samw * 1895331Samw * smb_fsop_getattr()/smb_vop_getattr() should always be called from the CIFS 1905331Samw * service (instead of calling VOP_GETATTR directly) to retrieve attributes 1915331Samw * due to special processing needed for streams files. 1925331Samw * 1935331Samw * All attributes are retrieved. 1945331Samw * 1955331Samw * A named stream's attributes (as far as CIFS is concerned) are those of the 1965331Samw * unnamed (i.e. data) stream (minus the size attribute), and the size of the 1975331Samw * named stream. Though the file system may store attributes other than size 1985331Samw * with the named stream, these should not be used by CIFS for any purpose. 1995331Samw * 2005331Samw * When vp denotes a named stream, then unnamed_vp should be passed in (denoting 2015331Samw * the corresponding unnamed stream). 2025331Samw */ 2035331Samw 2045331Samw int 2055331Samw smb_vop_getattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *ret_attr, 2065772Sas200622 int flags, cred_t *cr) 2075331Samw { 2085331Samw int error; 2095331Samw vnode_t *use_vp; 2105331Samw smb_attr_t tmp_attr; 2115331Samw xvattr_t tmp_xvattr; 2125331Samw xoptattr_t *xoap = NULL; 2135331Samw 2145331Samw if (unnamed_vp) 2155331Samw use_vp = unnamed_vp; 2165331Samw else 2175331Samw use_vp = vp; 2185331Samw 2195331Samw if (vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) { 2205331Samw xva_init(&tmp_xvattr); 2215331Samw xoap = xva_getxoptattr(&tmp_xvattr); 2225331Samw 2235331Samw ASSERT(xoap); 2245331Samw 2255331Samw smb_sa_to_va_mask(ret_attr->sa_mask, 2265331Samw &tmp_xvattr.xva_vattr.va_mask); 2275331Samw 2285331Samw XVA_SET_REQ(&tmp_xvattr, XAT_READONLY); 2295331Samw XVA_SET_REQ(&tmp_xvattr, XAT_HIDDEN); 2305331Samw XVA_SET_REQ(&tmp_xvattr, XAT_SYSTEM); 2315331Samw XVA_SET_REQ(&tmp_xvattr, XAT_ARCHIVE); 2325331Samw XVA_SET_REQ(&tmp_xvattr, XAT_CREATETIME); 2335331Samw 2345331Samw if ((error = VOP_GETATTR(use_vp, (vattr_t *)&tmp_xvattr, flags, 2355772Sas200622 cr, &smb_ct)) != 0) 2365331Samw return (error); 2375331Samw 2385331Samw ret_attr->sa_vattr = tmp_xvattr.xva_vattr; 2395331Samw 2405331Samw /* 2415331Samw * Copy special attributes to ret_attr parameter 2425331Samw */ 2435331Samw 2445331Samw ret_attr->sa_dosattr = 0; 2455331Samw 2465331Samw ASSERT(tmp_xvattr.xva_vattr.va_mask & AT_XVATTR); 2475331Samw 2485331Samw xoap = xva_getxoptattr(&tmp_xvattr); 2495331Samw ASSERT(xoap); 2505331Samw 2515331Samw if (XVA_ISSET_RTN(&tmp_xvattr, XAT_READONLY)) { 2525331Samw if (xoap->xoa_readonly) 2535331Samw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_READONLY; 2545331Samw } 2555331Samw 2565331Samw if (XVA_ISSET_RTN(&tmp_xvattr, XAT_HIDDEN)) { 2575331Samw if (xoap->xoa_hidden) 2585331Samw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_HIDDEN; 2595331Samw } 2605331Samw 2615331Samw if (XVA_ISSET_RTN(&tmp_xvattr, XAT_SYSTEM)) { 2625331Samw if (xoap->xoa_system) 2635331Samw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_SYSTEM; 2645331Samw } 2655331Samw 2665331Samw if (XVA_ISSET_RTN(&tmp_xvattr, XAT_ARCHIVE)) { 2675331Samw if (xoap->xoa_archive) 2685331Samw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_ARCHIVE; 2695331Samw } 2705331Samw 2715331Samw ret_attr->sa_crtime = xoap->xoa_createtime; 2725331Samw 2735331Samw if (unnamed_vp && (ret_attr->sa_mask & SMB_AT_SIZE)) { 2745331Samw /* 2755331Samw * Retrieve stream size attribute into temporary 2765331Samw * structure, in case the underlying file system 2775331Samw * returns attributes other than the size (we do not 2785331Samw * want to have ret_attr's other fields get 2795331Samw * overwritten). 2805331Samw * 2815331Samw * Note that vp is used here, and not use_vp. 2825331Samw * Also, only AT_SIZE is needed. 2835331Samw */ 2845331Samw 2855331Samw tmp_xvattr.xva_vattr.va_mask = AT_SIZE; 2865331Samw 2875331Samw if ((error = VOP_GETATTR(vp, (vattr_t *)&tmp_xvattr, 2885772Sas200622 flags, cr, &smb_ct)) != 0) 2895331Samw return (error); 2905331Samw 2915331Samw ret_attr->sa_vattr.va_size = 2925331Samw tmp_xvattr.xva_vattr.va_size; 2935331Samw 2945331Samw } 2955331Samw 2965331Samw if (ret_attr->sa_vattr.va_type == VDIR) { 2975331Samw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY; 2985331Samw } 2995331Samw 3005331Samw return (error); 3015331Samw } 3025331Samw 3035331Samw /* 3045331Samw * Support for file systems without VFSFT_XVATTR 3055331Samw */ 3065331Samw 3075331Samw smb_sa_to_va_mask(ret_attr->sa_mask, 3085331Samw &ret_attr->sa_vattr.va_mask); 3095331Samw 3105772Sas200622 error = VOP_GETATTR(use_vp, &ret_attr->sa_vattr, flags, cr, &smb_ct); 3115331Samw 3125331Samw if (error != 0) 3135331Samw return (error); 3145331Samw 3155331Samw /* 3165331Samw * "Fake" DOS attributes and create time, filesystem doesn't support 3175331Samw * them. 3185331Samw */ 3195331Samw 3205331Samw ret_attr->sa_dosattr = 0; 3215331Samw ret_attr->sa_crtime = ret_attr->sa_vattr.va_ctime; 3225331Samw 3235331Samw if (unnamed_vp && (ret_attr->sa_mask & SMB_AT_SIZE)) { 3245331Samw /* 3255331Samw * Retrieve stream size attribute into temporary structure, 3265331Samw * in case the underlying file system returns attributes 3275331Samw * other than the size (we do not want to have ret_attr's 3285331Samw * other fields get overwritten). 3295331Samw * 3305331Samw * Note that vp is used here, and not use_vp. 3315331Samw * Also, only AT_SIZE is needed. 3325331Samw */ 3335331Samw 3345331Samw tmp_attr.sa_vattr.va_mask = AT_SIZE; 3355772Sas200622 error = VOP_GETATTR(vp, &tmp_attr.sa_vattr, flags, cr, &smb_ct); 3365331Samw 3375331Samw if (error != 0) 3385331Samw return (error); 3395331Samw 3405331Samw 3415331Samw ret_attr->sa_vattr.va_size = tmp_attr.sa_vattr.va_size; 3425331Samw } 3435331Samw 3445331Samw if (ret_attr->sa_vattr.va_type == VDIR) { 3455331Samw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY; 3465331Samw } 3475331Samw 3485331Samw return (error); 3495331Samw } 3505331Samw 3515331Samw /* 3525331Samw * smb_vop_setattr() 3535331Samw * 354*6030Sjb150015 * smb_fsop_setattr()/smb_vop_setattr() should always be used instead of 355*6030Sjb150015 * VOP_SETATTR() when calling from the CIFS service, due to special processing 356*6030Sjb150015 * for streams files. 3575331Samw * 358*6030Sjb150015 * Streams have a size but otherwise do not have separate attributes from 359*6030Sjb150015 * the (unnamed stream) file, i.e., the security and ownership of the file 360*6030Sjb150015 * applies to the stream. In contrast, extended attribute files, which are 361*6030Sjb150015 * used to implement streams, are independent objects with their own 362*6030Sjb150015 * attributes. 363*6030Sjb150015 * 364*6030Sjb150015 * For compatibility with streams, we set the size on the extended attribute 365*6030Sjb150015 * file and apply other attributes to the (unnamed stream) file. The one 366*6030Sjb150015 * exception is that the UID and GID can be set on the stream by passing a 367*6030Sjb150015 * NULL unnamed_vp, which allows callers to synchronize stream ownership 368*6030Sjb150015 * with the (unnamed stream) file. 3695331Samw */ 3705331Samw 3715331Samw int 3725331Samw smb_vop_setattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *set_attr, 3735772Sas200622 int flags, cred_t *cr, boolean_t no_xvattr) 3745331Samw { 3755331Samw int error = 0; 3765331Samw int at_size = 0; 3775331Samw vnode_t *use_vp; 3785772Sas200622 xvattr_t xvattr; 3795772Sas200622 vattr_t *vap; 3805331Samw 3815331Samw if (unnamed_vp) { 3825331Samw use_vp = unnamed_vp; 3835331Samw if (set_attr->sa_mask & SMB_AT_SIZE) { 3845331Samw at_size = 1; 3855331Samw set_attr->sa_mask &= ~SMB_AT_SIZE; 3865331Samw } 3875331Samw } else { 3885331Samw use_vp = vp; 3895331Samw } 3905331Samw 3915331Samw /* 3925331Samw * The caller should not be setting sa_vattr.va_mask, 3935331Samw * but rather sa_mask. 3945331Samw */ 3955331Samw 3965331Samw set_attr->sa_vattr.va_mask = 0; 3975331Samw 3985521Sas200622 if ((no_xvattr == B_FALSE) && 3995521Sas200622 vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) { 4005331Samw 4015772Sas200622 smb_vop_setup_xvattr(set_attr, &xvattr); 4025772Sas200622 vap = (vattr_t *)&xvattr; 4035772Sas200622 } else { 4045331Samw smb_sa_to_va_mask(set_attr->sa_mask, 4055772Sas200622 &set_attr->sa_vattr.va_mask); 4065772Sas200622 vap = &set_attr->sa_vattr; 4075772Sas200622 } 4085331Samw 4095772Sas200622 if ((error = VOP_SETATTR(use_vp, vap, flags, cr, &smb_ct)) != 0) 4105772Sas200622 return (error); 4115331Samw 4125331Samw /* 4135772Sas200622 * If the size of the stream needs to be set, set it on 4145772Sas200622 * the stream file directly. (All other indicated attributes 415*6030Sjb150015 * are set on the stream's unnamed stream, except under the 416*6030Sjb150015 * exception described in the function header.) 4175331Samw */ 4185331Samw 4195331Samw if (at_size) { 4205331Samw /* 4215331Samw * set_attr->sa_vattr.va_size already contains the 4225331Samw * size as set by the caller 4235331Samw * 4245331Samw * Note that vp is used here, and not use_vp. 4255331Samw * Also, only AT_SIZE is needed. 4265331Samw */ 4275331Samw 4285331Samw set_attr->sa_vattr.va_mask = AT_SIZE; 4295772Sas200622 error = VOP_SETATTR(vp, &set_attr->sa_vattr, flags, cr, 4305772Sas200622 &smb_ct); 4315331Samw } 4325772Sas200622 4335331Samw return (error); 4345331Samw } 4355331Samw 4365331Samw /* 4375331Samw * smb_vop_access 4385331Samw * 4395331Samw * This is a wrapper round VOP_ACCESS. VOP_ACCESS checks the given mode 4405331Samw * against file's ACL or Unix permissions. CIFS on the other hand needs to 4415331Samw * know if the requested operation can succeed for the given object, this 4425331Samw * requires more checks in case of DELETE bit since permissions on the parent 4435331Samw * directory are important as well. Based on Windows rules if parent's ACL 4445331Samw * grant FILE_DELETE_CHILD a file can be delete regardless of the file's 4455331Samw * permissions. 4465331Samw */ 4475331Samw int 4485331Samw smb_vop_access(vnode_t *vp, int mode, int flags, vnode_t *dir_vp, cred_t *cr) 4495331Samw { 4505331Samw int error = 0; 4515331Samw 4525331Samw if (mode == 0) 4535331Samw return (0); 4545331Samw 4555331Samw if ((flags == V_ACE_MASK) && (mode & ACE_DELETE)) { 4565331Samw if (dir_vp) { 4575331Samw error = VOP_ACCESS(dir_vp, ACE_DELETE_CHILD, flags, 4585331Samw cr, NULL); 4595331Samw 4605331Samw if (error == 0) 4615331Samw mode &= ~ACE_DELETE; 4625331Samw } 4635331Samw } 4645331Samw 4655331Samw if (mode) { 4665331Samw error = VOP_ACCESS(vp, mode, flags, cr, NULL); 4675331Samw } 4685331Samw 4695331Samw return (error); 4705331Samw } 4715331Samw 4725331Samw /* 4735331Samw * smb_vop_lookup 4745331Samw * 4755331Samw * dvp: directory vnode (in) 4765331Samw * name: name of file to be looked up (in) 4775331Samw * vpp: looked-up vnode (out) 4785331Samw * od_name: on-disk name of file (out). 4795331Samw * This parameter is optional. If a pointer is passed in, it 4805331Samw * must be allocated with MAXNAMELEN bytes 4815331Samw * rootvp: vnode of the tree root (in) 4825331Samw * This parameter is always passed in non-NULL except at the time 4835331Samw * of share set up. 4845331Samw */ 4855331Samw 4865331Samw int 4875331Samw smb_vop_lookup(vnode_t *dvp, char *name, vnode_t **vpp, char *od_name, 4885772Sas200622 int flags, vnode_t *rootvp, cred_t *cr) 4895331Samw { 4905331Samw int error = 0; 4915331Samw int option_flags = 0; 4925331Samw pathname_t rpn; 4935331Samw 4945331Samw if (*name == '\0') 4955331Samw return (EINVAL); 4965331Samw 4975331Samw ASSERT(vpp); 4985331Samw *vpp = NULL; 4995331Samw 5005331Samw if ((name[0] == '.') && (name[1] == '.') && (name[2] == 0)) { 5015331Samw if (rootvp && (dvp == rootvp)) { 5025331Samw VN_HOLD(dvp); 5035331Samw *vpp = dvp; 5045331Samw return (0); 5055331Samw } 5065331Samw 5075331Samw if (dvp->v_flag & VROOT) { 5085331Samw vfs_t *vfsp; 5095331Samw vnode_t *cvp = dvp; 5105331Samw 5115331Samw /* 5125331Samw * Set dvp and check for races with forced unmount 5135331Samw * (see lookuppnvp()) 5145331Samw */ 5155331Samw 5165331Samw vfsp = cvp->v_vfsp; 5175331Samw vfs_rlock_wait(vfsp); 5185331Samw if (((dvp = cvp->v_vfsp->vfs_vnodecovered) == NULL) || 5195331Samw (cvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)) { 5205331Samw vfs_unlock(vfsp); 5215331Samw return (EIO); 5225331Samw } 5235331Samw vfs_unlock(vfsp); 5245331Samw } 5255331Samw } 5265331Samw 5275331Samw 5285331Samw 5295331Samw if (flags & SMB_IGNORE_CASE) 5305331Samw option_flags = FIGNORECASE; 5315331Samw 5325331Samw pn_alloc(&rpn); 5335331Samw 5345331Samw error = VOP_LOOKUP(dvp, name, vpp, NULL, option_flags, NULL, cr, 5355772Sas200622 &smb_ct, NULL, &rpn); 5365331Samw 5375331Samw if ((error == 0) && od_name) { 5385331Samw bzero(od_name, MAXNAMELEN); 5395331Samw if (option_flags == FIGNORECASE) 5405331Samw (void) strlcpy(od_name, rpn.pn_buf, MAXNAMELEN); 5415331Samw else 5425331Samw (void) strlcpy(od_name, name, MAXNAMELEN); 5435331Samw } 5445331Samw 5455331Samw pn_free(&rpn); 5465331Samw return (error); 5475331Samw } 5485331Samw 5495331Samw int 5505331Samw smb_vop_create(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp, 5515772Sas200622 int flags, cred_t *cr, vsecattr_t *vsap) 5525772Sas200622 { 5535772Sas200622 int error; 5545772Sas200622 int option_flags = 0; 5555772Sas200622 xvattr_t xvattr; 5565772Sas200622 vattr_t *vap; 5575772Sas200622 5585772Sas200622 if (flags & SMB_IGNORE_CASE) 5595772Sas200622 option_flags = FIGNORECASE; 5605772Sas200622 5615772Sas200622 attr->sa_vattr.va_mask = 0; 5625772Sas200622 5635772Sas200622 if (vfs_has_feature(dvp->v_vfsp, VFSFT_XVATTR)) { 5645772Sas200622 smb_vop_setup_xvattr(attr, &xvattr); 5655772Sas200622 vap = (vattr_t *)&xvattr; 5665772Sas200622 } else { 5675772Sas200622 smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask); 5685772Sas200622 vap = &attr->sa_vattr; 5695772Sas200622 } 5705772Sas200622 5715772Sas200622 error = VOP_CREATE(dvp, name, vap, EXCL, attr->sa_vattr.va_mode, 5725772Sas200622 vpp, cr, option_flags, &smb_ct, vsap); 5735772Sas200622 5745772Sas200622 return (error); 5755772Sas200622 } 5765772Sas200622 5775772Sas200622 int 5785772Sas200622 smb_vop_remove(vnode_t *dvp, char *name, int flags, cred_t *cr) 5795331Samw { 5805331Samw int error; 5815331Samw int option_flags = 0; 5825331Samw 5835331Samw if (flags & SMB_IGNORE_CASE) 5845331Samw option_flags = FIGNORECASE; 5855331Samw 5865772Sas200622 error = VOP_REMOVE(dvp, name, cr, &smb_ct, option_flags); 5875331Samw 5885331Samw return (error); 5895331Samw } 5905331Samw 5915331Samw /* 5925331Samw * smb_vop_rename() 5935331Samw * 5945331Samw * The rename is for files in the same tree (identical TID) only. 5955331Samw */ 5965331Samw 5975331Samw int 5985331Samw smb_vop_rename(vnode_t *from_dvp, char *from_name, vnode_t *to_dvp, 5995772Sas200622 char *to_name, int flags, cred_t *cr) 6005331Samw { 6015331Samw int error; 6025331Samw int option_flags = 0; 6035331Samw 6045331Samw 6055331Samw if (flags & SMB_IGNORE_CASE) 6065331Samw option_flags = FIGNORECASE; 6075331Samw 6085331Samw error = VOP_RENAME(from_dvp, from_name, to_dvp, to_name, cr, 6095772Sas200622 &smb_ct, option_flags); 6105331Samw 6115331Samw return (error); 6125331Samw } 6135331Samw 6145331Samw int 6155331Samw smb_vop_mkdir(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp, 6165772Sas200622 int flags, cred_t *cr, vsecattr_t *vsap) 6175331Samw { 6185331Samw int error; 6195331Samw int option_flags = 0; 6205331Samw 6215331Samw 6225331Samw 6235331Samw if (flags & SMB_IGNORE_CASE) 6245331Samw option_flags = FIGNORECASE; 6255331Samw 6265331Samw smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask); 6275331Samw 6285772Sas200622 error = VOP_MKDIR(dvp, name, &attr->sa_vattr, vpp, cr, &smb_ct, 6295331Samw option_flags, vsap); 6305331Samw 6315331Samw return (error); 6325331Samw } 6335331Samw 6345331Samw /* 6355331Samw * smb_vop_rmdir() 6365331Samw * 6375331Samw * Only simple rmdir supported, consistent with NT semantics 6385331Samw * (can only remove an empty directory). 6395331Samw * 6405331Samw */ 6415331Samw 6425331Samw int 6435772Sas200622 smb_vop_rmdir(vnode_t *dvp, char *name, int flags, cred_t *cr) 6445331Samw { 6455331Samw int error; 6465331Samw int option_flags = 0; 6475331Samw 6485331Samw if (flags & SMB_IGNORE_CASE) 6495331Samw option_flags = FIGNORECASE; 6505331Samw 6515331Samw /* 6525331Samw * Comments adapted from rfs_rmdir(). 6535331Samw * 6545331Samw * VOP_RMDIR now takes a new third argument (the current 6555331Samw * directory of the process). That's because rmdir 6565331Samw * wants to return EINVAL if one tries to remove ".". 6575331Samw * Of course, SMB servers do not know what their 6585331Samw * clients' current directories are. We fake it by 6595331Samw * supplying a vnode known to exist and illegal to 6605331Samw * remove. 6615331Samw */ 6625331Samw 6635772Sas200622 error = VOP_RMDIR(dvp, name, rootdir, cr, &smb_ct, option_flags); 6645331Samw return (error); 6655331Samw } 6665331Samw 6675331Samw int 6685772Sas200622 smb_vop_commit(vnode_t *vp, cred_t *cr) 6695772Sas200622 { 6705772Sas200622 return (VOP_FSYNC(vp, 1, cr, &smb_ct)); 6715772Sas200622 } 6725772Sas200622 6735772Sas200622 void 6745772Sas200622 smb_vop_setup_xvattr(smb_attr_t *smb_attr, xvattr_t *xvattr) 6755331Samw { 6765772Sas200622 xoptattr_t *xoap = NULL; 6775772Sas200622 uint_t xva_mask; 6785772Sas200622 6795772Sas200622 /* 6805772Sas200622 * Initialize xvattr, including bzero 6815772Sas200622 */ 6825772Sas200622 xva_init(xvattr); 6835772Sas200622 xoap = xva_getxoptattr(xvattr); 6845772Sas200622 6855772Sas200622 ASSERT(xoap); 6865772Sas200622 6875772Sas200622 /* 6885772Sas200622 * Copy caller-specified classic attributes to xvattr. 6895772Sas200622 * First save xvattr's mask (set in xva_init()), which 6905772Sas200622 * contains AT_XVATTR. This is |'d in later if needed. 6915772Sas200622 */ 6925772Sas200622 6935772Sas200622 xva_mask = xvattr->xva_vattr.va_mask; 6945772Sas200622 xvattr->xva_vattr = smb_attr->sa_vattr; 6955772Sas200622 6965772Sas200622 smb_sa_to_va_mask(smb_attr->sa_mask, &xvattr->xva_vattr.va_mask); 6975772Sas200622 6985772Sas200622 /* 6995772Sas200622 * Do not set ctime (only the file system can do it) 7005772Sas200622 */ 7015772Sas200622 7025772Sas200622 xvattr->xva_vattr.va_mask &= ~AT_CTIME; 7035772Sas200622 7045772Sas200622 if (smb_attr->sa_mask & SMB_AT_DOSATTR) { 7055772Sas200622 7065772Sas200622 /* 7075772Sas200622 * "|" in the original xva_mask, which contains 7085772Sas200622 * AT_XVATTR 7095772Sas200622 */ 7105772Sas200622 7115772Sas200622 xvattr->xva_vattr.va_mask |= xva_mask; 7125772Sas200622 7135772Sas200622 XVA_SET_REQ(xvattr, XAT_ARCHIVE); 7145772Sas200622 XVA_SET_REQ(xvattr, XAT_SYSTEM); 7155772Sas200622 XVA_SET_REQ(xvattr, XAT_READONLY); 7165772Sas200622 XVA_SET_REQ(xvattr, XAT_HIDDEN); 7175772Sas200622 7185772Sas200622 /* 7195772Sas200622 * smb_attr->sa_dosattr: If a given bit is not set, 7205772Sas200622 * that indicates that the corresponding field needs 7215772Sas200622 * to be updated with a "0" value. This is done 7225772Sas200622 * implicitly as the xoap->xoa_* fields were bzero'd. 7235772Sas200622 */ 7245772Sas200622 7255772Sas200622 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_ARCHIVE) 7265772Sas200622 xoap->xoa_archive = 1; 7275772Sas200622 7285772Sas200622 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_SYSTEM) 7295772Sas200622 xoap->xoa_system = 1; 7305772Sas200622 7315772Sas200622 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_READONLY) 7325772Sas200622 xoap->xoa_readonly = 1; 7335772Sas200622 7345772Sas200622 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_HIDDEN) 7355772Sas200622 xoap->xoa_hidden = 1; 7365772Sas200622 } 7375772Sas200622 7385772Sas200622 if (smb_attr->sa_mask & SMB_AT_CRTIME) { 7395772Sas200622 /* 7405772Sas200622 * "|" in the original xva_mask, which contains 7415772Sas200622 * AT_XVATTR 7425772Sas200622 */ 7435772Sas200622 7445772Sas200622 xvattr->xva_vattr.va_mask |= xva_mask; 7455772Sas200622 XVA_SET_REQ(xvattr, XAT_CREATETIME); 7465772Sas200622 xoap->xoa_createtime = smb_attr->sa_crtime; 7475772Sas200622 } 7485331Samw } 7495331Samw 7505772Sas200622 7515331Samw /* 7525331Samw * smb_vop_readdir() 7535331Samw * 7545331Samw * Upon return, the "name" field will contain either the on-disk name or, if 7555331Samw * it needs mangling or has a case-insensitive collision, the mangled 7565331Samw * "shortname." 7575331Samw * 7585331Samw * vpp is an optional parameter. If non-NULL, it will contain a pointer to 7595331Samw * the vnode for the name that is looked up (the vnode will be returned held). 7605331Samw * 7615331Samw * od_name is an optional parameter (NULL can be passed if the on-disk name 7625331Samw * is not needed by the caller). 7635331Samw */ 7645331Samw 7655331Samw int 7665331Samw smb_vop_readdir(vnode_t *dvp, uint32_t *cookiep, char *name, int *namelen, 7675772Sas200622 ino64_t *inop, vnode_t **vpp, char *od_name, int flags, cred_t *cr) 7685331Samw { 7695331Samw int num_bytes; 7705331Samw int error = 0; 7715331Samw char *dirbuf = NULL; 7725331Samw 7735331Samw ASSERT(dvp); 7745331Samw ASSERT(cookiep); 7755331Samw ASSERT(name); 7765331Samw ASSERT(namelen); 7775331Samw ASSERT(inop); 7785331Samw ASSERT(cr); 7795331Samw 7805331Samw if (dvp->v_type != VDIR) { 7815331Samw *namelen = 0; 7825331Samw return (ENOTDIR); 7835331Samw } 7845331Samw 7855331Samw if (vpp) 7865331Samw *vpp = NULL; 7875331Samw 7885331Samw dirbuf = kmem_zalloc(SMB_MINLEN_RDDIR_BUF, KM_SLEEP); 7895331Samw num_bytes = SMB_MINLEN_RDDIR_BUF; 7905331Samw 7915331Samw /* 7925331Samw * The goal is to retrieve the first valid entry from *cookiep 7935331Samw * forward. smb_vop_readdir_readpage() collects an 7945331Samw * SMB_MINLEN_RDDIR_BUF-size "page" of directory entry information. 7955331Samw * smb_vop_readdir_entry() attempts to find the first valid entry 7965331Samw * in that page. 7975331Samw */ 7985331Samw 7995331Samw while ((error = smb_vop_readdir_readpage(dvp, dirbuf, *cookiep, 8005772Sas200622 &num_bytes, cr, flags)) == 0) { 8015331Samw 8025331Samw if (num_bytes <= 0) 8035331Samw break; 8045331Samw 8055331Samw name[0] = '\0'; 8065331Samw 8075331Samw error = smb_vop_readdir_entry(dvp, cookiep, name, namelen, 8085772Sas200622 inop, vpp, od_name, flags, cr, dirbuf, 8095331Samw num_bytes); 8105331Samw 8115331Samw if (error) 8125331Samw break; 8135331Samw 8145331Samw if (*name) 8155331Samw break; 8165331Samw 8175331Samw bzero(dirbuf, SMB_MINLEN_RDDIR_BUF); 8185331Samw num_bytes = SMB_MINLEN_RDDIR_BUF; 8195331Samw } 8205331Samw 8215331Samw 8225331Samw if (error) { 8235331Samw kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 8245331Samw *namelen = 0; 8255331Samw return (error); 8265331Samw } 8275331Samw 8285331Samw if (num_bytes == 0) { /* EOF */ 8295331Samw kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 8305331Samw *cookiep = SMB_EOF; 8315331Samw *namelen = 0; 8325331Samw return (0); 8335331Samw } 8345331Samw 8355331Samw kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 8365331Samw return (0); 8375331Samw } 8385331Samw 8395331Samw /* 8405331Samw * smb_vop_readdir_readpage() 8415331Samw * 8425331Samw * Collects an SMB_MINLEN_RDDIR_BUF "page" of directory entries. (The 8435331Samw * directory entries are returned in an fs-independent format by the 8445331Samw * underlying file system. That is, the "page" of information returned is 8455331Samw * not literally stored on-disk in the format returned.) 8465331Samw * 8475331Samw * Much of the following is borrowed from getdents64() 8485331Samw * 8495331Samw * MAXGETDENTS_SIZE is defined in getdents.c 8505331Samw */ 8515331Samw 8525331Samw #define MAXGETDENTS_SIZE (64 * 1024) 8535331Samw 8545331Samw static int 8555331Samw smb_vop_readdir_readpage(vnode_t *vp, void *buf, uint32_t offset, int *count, 8565772Sas200622 cred_t *cr, int flags) 8575331Samw { 8585331Samw int error = 0; 8595331Samw int rdirent_flags = 0; 8605331Samw int sink; 8615331Samw struct uio auio; 8625331Samw struct iovec aiov; 8635331Samw 8645331Samw if (vp->v_type != VDIR) 8655331Samw return (ENOTDIR); 8665331Samw 8675331Samw /* entflags not working for streams so don't try to use them */ 8685331Samw if (!(flags & SMB_STREAM_RDDIR) && 8695331Samw (vfs_has_feature(vp->v_vfsp, VFSFT_DIRENTFLAGS))) { 8705331Samw /* 8715331Samw * Setting V_RDDIR_ENTFLAGS will cause the buffer to 8725331Samw * be filled with edirent_t structures (instead of 8735331Samw * dirent64_t structures). 8745331Samw */ 8755331Samw rdirent_flags = V_RDDIR_ENTFLAGS; 8765331Samw 8775331Samw if (*count < sizeof (edirent_t)) 8785331Samw return (EINVAL); 8795331Samw } else { 8805331Samw if (*count < sizeof (dirent64_t)) 8815331Samw return (EINVAL); 8825331Samw } 8835331Samw 8845331Samw if (*count > MAXGETDENTS_SIZE) 8855331Samw *count = MAXGETDENTS_SIZE; 8865331Samw 8875331Samw aiov.iov_base = buf; 8885331Samw aiov.iov_len = *count; 8895331Samw auio.uio_iov = &aiov; 8905331Samw auio.uio_iovcnt = 1; 8915331Samw auio.uio_loffset = (uint64_t)offset; 8925331Samw auio.uio_segflg = UIO_SYSSPACE; 8935331Samw auio.uio_resid = *count; 8945331Samw auio.uio_fmode = 0; 8955331Samw 8965331Samw (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL); 8975772Sas200622 error = VOP_READDIR(vp, &auio, cr, &sink, &smb_ct, rdirent_flags); 8985331Samw VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL); 8995331Samw 9005331Samw if (error) { 9015331Samw if (error == ENOENT) { 9025331Samw /* Fake EOF if offset is bad due to dropping of lock */ 9035331Samw *count = 0; 9045331Samw return (0); 9055331Samw } else { 9065331Samw return (error); 9075331Samw } 9085331Samw } 9095331Samw 9105331Samw /* 9115331Samw * Windows cannot handle an offset > SMB_EOF. 9125331Samw * Pretend we are at EOF. 9135331Samw */ 9145331Samw 9155331Samw if (auio.uio_loffset > SMB_EOF) { 9165331Samw *count = 0; 9175331Samw return (0); 9185331Samw } 9195331Samw 9205331Samw *count = *count - auio.uio_resid; 9215331Samw return (0); 9225331Samw } 9235331Samw 9245331Samw /* 9255331Samw * smb_vop_readdir_entry() 9265331Samw * 9275331Samw * This function retrieves the first valid entry from the 9285331Samw * SMB_MINLEN_RDDIR_BUF-sized buffer returned by smb_vop_readdir_readpage() 9295331Samw * to smb_vop_readdir(). 9305331Samw * 9315331Samw * Both dirent64_t and edirent_t structures need to be handled. The former is 9325331Samw * needed for file systems that do not support VFSFT_DIRENTFLAGS. The latter 9335331Samw * is required for proper handling of case collisions on file systems that 9345331Samw * support case-insensitivity. edirent_t structures are also used for 9355331Samw * case-sensitive file systems if VFSFT_DIRENTFLAGS is supported. 9365331Samw */ 9375331Samw 9385331Samw static int 9395331Samw smb_vop_readdir_entry(vnode_t *dvp, uint32_t *cookiep, char *name, int *namelen, 9405331Samw ino64_t *inop, vnode_t **vpp, char *od_name, int flags, cred_t *cr, 9415772Sas200622 char *dirbuf, int num_bytes) 9425331Samw { 9435331Samw uint32_t next_cookie; 9445331Samw int ebufsize; 9455331Samw int error = 0; 9465331Samw int len; 9475331Samw int rc; 9485331Samw char shortname[MANGLE_NAMELEN]; 9495331Samw char name83[MANGLE_NAMELEN]; 9505331Samw char *ebuf = NULL; 9515331Samw edirent_t *edp; 9525331Samw dirent64_t *dp = NULL; 9535331Samw vnode_t *vp = NULL; 9545331Samw 9555331Samw ASSERT(dirbuf); 9565331Samw 9575331Samw /* 9585331Samw * Use edirent_t structure for both 9595331Samw * entflags not working for streams so don't try to use them 9605331Samw */ 9615331Samw if (!(flags & SMB_STREAM_RDDIR) && 9625331Samw (vfs_has_feature(dvp->v_vfsp, VFSFT_DIRENTFLAGS))) { 9635331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 9645331Samw edp = (edirent_t *)dirbuf; 9655331Samw } else { 9665331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 9675331Samw dp = (dirent64_t *)dirbuf; 9685331Samw ebufsize = EDIRENT_RECLEN(MAXNAMELEN); 9695331Samw ebuf = kmem_zalloc(ebufsize, KM_SLEEP); 9705331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 9715331Samw edp = (edirent_t *)ebuf; 9725331Samw } 9735331Samw 9745331Samw while (edp) { 9755331Samw if (dp) 9765331Samw DP_TO_EDP(dp, edp); 9775331Samw 9785331Samw next_cookie = (uint32_t)edp->ed_off; 9795331Samw if (edp->ed_ino == 0) { 9805331Samw *cookiep = next_cookie; 9815331Samw 9825331Samw if (dp) { 9835331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 9845331Samw DP_ADVANCE(dp, dirbuf, num_bytes); 9855331Samw if (dp == NULL) 9865331Samw edp = NULL; 9875331Samw } else { 9885331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 9895331Samw EDP_ADVANCE(edp, dirbuf, num_bytes); 9905331Samw } 9915331Samw continue; 9925331Samw } 9935331Samw 9945331Samw len = strlen(edp->ed_name); 9955331Samw 9965331Samw if (*namelen < len) { 9975331Samw *namelen = 0; 9985331Samw 9995331Samw if (ebuf) 10005331Samw kmem_free(ebuf, ebufsize); 10015331Samw 10025331Samw return (EOVERFLOW); 10035331Samw } 10045331Samw 10055331Samw /* 10065331Samw * Do not pass SMB_IGNORE_CASE to smb_vop_lookup 10075331Samw */ 10085331Samw 10095331Samw error = smb_vop_lookup(dvp, edp->ed_name, vpp ? vpp : &vp, 10105772Sas200622 od_name, 0, NULL, cr); 10115331Samw 10125331Samw if (error) { 10135331Samw if (error == ENOENT) { 10145331Samw *cookiep = (uint32_t)next_cookie; 10155331Samw 10165331Samw if (dp) { 10175331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 10185331Samw DP_ADVANCE(dp, dirbuf, num_bytes); 10195331Samw if (dp == NULL) 10205331Samw edp = NULL; 10215331Samw } else { 10225331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 10235331Samw EDP_ADVANCE(edp, dirbuf, num_bytes); 10245331Samw } 10255331Samw continue; 10265331Samw } 10275331Samw 10285331Samw 10295331Samw *namelen = 0; 10305331Samw 10315331Samw if (ebuf) 10325331Samw kmem_free(ebuf, ebufsize); 10335331Samw 10345331Samw return (error); 10355331Samw } 10365331Samw 10375331Samw if ((flags & SMB_IGNORE_CASE) && ED_CASE_CONFLICTS(edp)) { 10385331Samw rc = smb_mangle_name(edp->ed_ino, edp->ed_name, 10395331Samw shortname, name83, 1); 10405331Samw 10415331Samw if (rc == 1) { /* success */ 10425331Samw (void) strlcpy(name, shortname, *namelen + 1); 10435331Samw *namelen = strlen(shortname); 10445331Samw } else { 10455331Samw (void) strlcpy(name, edp->ed_name, 10465331Samw *namelen + 1); 10475331Samw name[*namelen] = '\0'; 10485331Samw } 10495331Samw 10505331Samw } else { 10515331Samw (void) strlcpy(name, edp->ed_name, *namelen + 1); 10525331Samw *namelen = len; 10535331Samw } 10545331Samw 10555331Samw if (vpp == NULL) 10565331Samw VN_RELE(vp); 10575331Samw 10585331Samw if (inop) 10595331Samw *inop = edp->ed_ino; 10605331Samw 10615331Samw *cookiep = (uint32_t)next_cookie; 10625331Samw break; 10635331Samw } 10645331Samw 10655331Samw if (ebuf) 10665331Samw kmem_free(ebuf, ebufsize); 10675331Samw 10685331Samw return (error); 10695331Samw } 10705331Samw 10715331Samw /* 10725331Samw * smb_sa_to_va_mask 10735331Samw * 10745331Samw * Set va_mask by running through the SMB_AT_* #define's and 10755331Samw * setting those bits that correspond to the SMB_AT_* bits 10765331Samw * set in sa_mask. 10775331Samw */ 10785331Samw 10795331Samw void 10805331Samw smb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp) 10815331Samw { 10825331Samw int i; 10835331Samw uint_t smask; 10845331Samw 10855331Samw smask = (sa_mask); 10865331Samw for (i = SMB_AT_TYPE; (i < SMB_AT_MAX) && (smask != 0); ++i) { 10875331Samw if (smask & 1) 10885331Samw *(va_maskp) |= smb_attrmap[i]; 10895331Samw 10905331Samw smask >>= 1; 10915331Samw } 10925331Samw } 10935331Samw 10945331Samw /* 10955331Samw * smb_vop_getdents() 10965331Samw * 10975331Samw * Upon success, the smb_node corresponding to each entry returned will 10985331Samw * have a reference taken on it. These will be released in 10995331Samw * smb_trans2_find_get_dents(). 11005331Samw * 11015331Samw * If an error is returned from this routine, a list of already processed 11025331Samw * entries will be returned. The smb_nodes corresponding to these entries 11035331Samw * will be referenced, and will be released in smb_trans2_find_get_dents(). 11045331Samw * 11055331Samw * The returned dp->d_name field will contain either the on-disk name or, if 11065331Samw * it needs mangling or has a case-insensitive collision, the mangled 11075331Samw * "shortname." In this case, the on-disk name can be retrieved from the 11085331Samw * smb_node's od_name (the smb_node is passed to smb_gather_dents_info()). 11095331Samw */ 11105331Samw 11115331Samw int /*ARGSUSED*/ 11125331Samw smb_vop_getdents( 11135331Samw smb_node_t *dir_snode, 11145331Samw uint32_t *cookiep, 11155331Samw uint64_t *verifierp, 11165331Samw int32_t *dircountp, 11175331Samw char *arg, 11185331Samw char *pattern, 11195331Samw uint32_t flags, 11205331Samw smb_request_t *sr, 11215772Sas200622 cred_t *cr) 11225331Samw { 11235331Samw int error = 0; 11245331Samw int maxentries; 11255331Samw int num_bytes; 11265331Samw int resid; 11275331Samw char *dirbuf = NULL; 11285331Samw vnode_t *dvp; 11295331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 11305331Samw smb_dent_info_hdr_t *ihdr = (smb_dent_info_hdr_t *)arg; 11315331Samw 11325331Samw dvp = dir_snode->vp; 11335331Samw 11345331Samw resid = ihdr->uio.uio_resid; 11355331Samw maxentries = resid / SMB_MAX_DENT_INFO_SIZE; 11365331Samw 11375331Samw bzero(ihdr->iov->iov_base, resid); 11385331Samw 11395331Samw dirbuf = kmem_alloc(SMB_MINLEN_RDDIR_BUF, KM_SLEEP); 11405331Samw 11415331Samw while (maxentries) { 11425331Samw 11435331Samw bzero(dirbuf, SMB_MINLEN_RDDIR_BUF); 11445331Samw 11455331Samw num_bytes = SMB_MINLEN_RDDIR_BUF; 11465331Samw error = smb_vop_readdir_readpage(dvp, dirbuf, *cookiep, 11475772Sas200622 &num_bytes, cr, flags); 11485331Samw 11495331Samw if (error || (num_bytes <= 0)) 11505331Samw break; 11515331Samw 11525331Samw error = smb_vop_getdents_entries(dir_snode, cookiep, dircountp, 11535772Sas200622 arg, flags, sr, cr, dirbuf, &maxentries, num_bytes, 11545331Samw pattern); 11555331Samw 11565331Samw if (error) 11575331Samw goto out; 11585331Samw } 11595331Samw 11605331Samw if (num_bytes < 0) { 11615331Samw error = -1; 11625331Samw } else if (num_bytes == 0) { 11635331Samw *cookiep = SMB_EOF; 11645331Samw error = 0; 11655331Samw } else { 11665331Samw error = 0; 11675331Samw } 11685331Samw 11695331Samw out: 11705331Samw if (dirbuf) 11715331Samw kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 11725331Samw 11735331Samw return (error); 11745331Samw } 11755331Samw 11765331Samw /* 11775331Samw * smb_vop_getdents_entries() 11785331Samw * 11795331Samw * This function retrieves names from the SMB_MINLEN_RDDIR_BUF-sized buffer 11805331Samw * returned by smb_vop_readdir_readpage() to smb_vop_getdents(). 11815331Samw * 11825331Samw * Both dirent64_t and edirent_t structures need to be handled. The former is 11835331Samw * needed for file systems that do not support VFSFT_DIRENTFLAGS. The latter 11845331Samw * is required for properly handling case collisions on file systems that 11855331Samw * support case-insensitivity. edirent_t is also used on case-sensitive 11865331Samw * file systems where VFSFT_DIRENTFLAGS is available. 11875331Samw */ 11885331Samw 11895331Samw static int 11905331Samw smb_vop_getdents_entries( 11915331Samw smb_node_t *dir_snode, 11925331Samw uint32_t *cookiep, 11935331Samw int32_t *dircountp, 11945331Samw char *arg, 11955331Samw uint32_t flags, 11965331Samw struct smb_request *sr, 11975331Samw cred_t *cr, 11985331Samw char *dirbuf, 11995331Samw int *maxentries, 12005331Samw int num_bytes, 12015331Samw char *pattern) 12025331Samw { 12035331Samw uint32_t next_cookie; 12045331Samw int ebufsize; 12055331Samw char *tmp_name; 12065331Samw int error; 12075331Samw int rc; 12085331Samw char shortname[MANGLE_NAMELEN]; 12095331Samw char name83[MANGLE_NAMELEN]; 12105331Samw char *ebuf = NULL; 12115331Samw dirent64_t *dp = NULL; 12125331Samw edirent_t *edp; 12135331Samw smb_node_t *ret_snode; 12145331Samw smb_attr_t ret_attr; 12155331Samw vnode_t *dvp; 12165331Samw vnode_t *fvp; 12175331Samw 12185331Samw ASSERT(dirbuf); 12195331Samw 12205331Samw dvp = dir_snode->vp; 12215331Samw 12225331Samw if (vfs_has_feature(dvp->v_vfsp, VFSFT_DIRENTFLAGS)) { 12235331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 12245331Samw edp = (edirent_t *)dirbuf; 12255331Samw } else { 12265331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 12275331Samw dp = (dirent64_t *)dirbuf; 12285331Samw ebufsize = EDIRENT_RECLEN(MAXNAMELEN); 12295331Samw ebuf = kmem_zalloc(ebufsize, KM_SLEEP); 12305331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 12315331Samw edp = (edirent_t *)ebuf; 12325331Samw } 12335331Samw 12345331Samw while (edp) { 12355331Samw if (dp) 12365331Samw DP_TO_EDP(dp, edp); 12375331Samw 12385331Samw if (*maxentries == 0) 12395331Samw break; 12405331Samw 12415331Samw next_cookie = (uint32_t)edp->ed_off; 12425331Samw 12435331Samw if (edp->ed_ino == 0) { 12445331Samw *cookiep = next_cookie; 12455331Samw if (dp) { 12465331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 12475331Samw DP_ADVANCE(dp, dirbuf, num_bytes); 12485331Samw if (dp == NULL) 12495331Samw edp = NULL; 12505331Samw } else { 12515331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 12525331Samw EDP_ADVANCE(edp, dirbuf, num_bytes); 12535331Samw } 12545331Samw continue; 12555331Samw } 12565331Samw 12575331Samw error = smb_vop_lookup(dvp, edp->ed_name, &fvp, 12585772Sas200622 NULL, 0, NULL, cr); 12595331Samw 12605331Samw if (error) { 12615331Samw if (error == ENOENT) { 12625331Samw *cookiep = next_cookie; 12635331Samw if (dp) { 12645331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 12655331Samw DP_ADVANCE(dp, dirbuf, 12665331Samw num_bytes); 12675331Samw if (dp == NULL) 12685331Samw edp = NULL; 12695331Samw } else { 12705331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 12715331Samw EDP_ADVANCE(edp, dirbuf, 12725331Samw num_bytes); 12735331Samw } 12745331Samw continue; 12755331Samw } 12765331Samw if (ebuf) 12775331Samw kmem_free(ebuf, ebufsize); 12785331Samw 12795331Samw return (error); 12805331Samw } 12815331Samw 12825331Samw ret_snode = smb_node_lookup(sr, NULL, cr, fvp, 12835331Samw edp->ed_name, dir_snode, NULL, &ret_attr); 12845331Samw 12855331Samw if (ret_snode == NULL) { 12865331Samw VN_RELE(fvp); 12875331Samw 12885331Samw if (ebuf) 12895331Samw kmem_free(ebuf, ebufsize); 12905331Samw 12915331Samw return (ENOMEM); 12925331Samw } 12935331Samw 12945331Samw if (smb_match_name(edp->ed_ino, edp->ed_name, shortname, 12955331Samw name83, pattern, (flags & SMB_IGNORE_CASE))) { 12965331Samw 12975331Samw tmp_name = edp->ed_name; 12985331Samw 12995331Samw if ((flags & SMB_IGNORE_CASE) && 13005331Samw ED_CASE_CONFLICTS(edp)) { 13015331Samw rc = smb_mangle_name(edp->ed_ino, edp->ed_name, 13025331Samw shortname, name83, 1); 13035331Samw if (rc == 1) 13045331Samw tmp_name = shortname; 13055331Samw } else { 13065331Samw rc = smb_mangle_name(edp->ed_ino, edp->ed_name, 13075331Samw shortname, name83, 0); 13085331Samw } 13095331Samw 13105331Samw if (rc != 1) { 13115331Samw (void) strlcpy(shortname, edp->ed_name, 13125331Samw MANGLE_NAMELEN); 13135331Samw (void) strlcpy(name83, edp->ed_name, 13145331Samw MANGLE_NAMELEN); 13155331Samw shortname[MANGLE_NAMELEN - 1] = '\0'; 13165331Samw name83[MANGLE_NAMELEN - 1] = '\0'; 13175331Samw } 13185331Samw 13195331Samw error = smb_gather_dents_info(arg, edp->ed_ino, 13205331Samw strlen(tmp_name), tmp_name, next_cookie, dircountp, 13215331Samw &ret_attr, ret_snode, shortname, name83); 13225331Samw 13235331Samw if (error > 0) { 13245331Samw if (ebuf) 13255331Samw kmem_free(ebuf, ebufsize); 13265331Samw return (error); 13275331Samw } 13285331Samw 13295331Samw /* 13305331Samw * Treat errors from smb_gather_dents_info() that are 13315331Samw * < 0 the same as EOF. 13325331Samw */ 13335331Samw if (error < 0) { 13345331Samw if (ebuf) 13355331Samw kmem_free(ebuf, ebufsize); 13365331Samw *maxentries = 0; 13375331Samw return (0); 13385331Samw } 13395331Samw (*maxentries)--; 13405331Samw } else { 13415331Samw smb_node_release(ret_snode); 13425331Samw } 13435331Samw 13445331Samw *cookiep = next_cookie; 13455331Samw 13465331Samw if (dp) { 13475331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 13485331Samw DP_ADVANCE(dp, dirbuf, num_bytes); 13495331Samw if (dp == NULL) 13505331Samw edp = NULL; 13515331Samw } else { 13525331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 13535331Samw EDP_ADVANCE(edp, dirbuf, num_bytes); 13545331Samw } 13555331Samw } 13565331Samw 13575331Samw if (ebuf) 13585331Samw kmem_free(ebuf, ebufsize); 13595331Samw 13605331Samw return (0); 13615331Samw } 13625331Samw 13635331Samw /* 13645331Samw * smb_vop_stream_lookup() 13655331Samw * 13665331Samw * The name returned in od_name is the on-disk name of the stream with the 13675331Samw * SMB_STREAM_PREFIX stripped off. od_name should be allocated to MAXNAMELEN 13685331Samw * by the caller. 13695331Samw */ 13705331Samw 13715331Samw int 13725331Samw smb_vop_stream_lookup(vnode_t *fvp, char *stream_name, vnode_t **vpp, 13735331Samw char *od_name, vnode_t **xattrdirvpp, int flags, vnode_t *rootvp, 13745772Sas200622 cred_t *cr) 13755331Samw { 13765331Samw char *solaris_stream_name; 13775331Samw char *name; 13785331Samw int error; 13795331Samw 13805331Samw if ((error = smb_vop_lookup_xattrdir(fvp, xattrdirvpp, 13815772Sas200622 LOOKUP_XATTR | CREATE_XATTR_DIR, cr)) != 0) 13825331Samw return (error); 13835331Samw 13845331Samw /* 13855331Samw * Prepend SMB_STREAM_PREFIX to stream name 13865331Samw */ 13875331Samw 13885331Samw solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 13895331Samw (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX, 13905331Samw stream_name); 13915331Samw 13925331Samw /* 13935331Samw * "name" will hold the on-disk name returned from smb_vop_lookup 13945331Samw * for the stream, including the SMB_STREAM_PREFIX. 13955331Samw */ 13965331Samw 13975331Samw name = kmem_zalloc(MAXNAMELEN, KM_SLEEP); 13985331Samw 13995331Samw if ((error = smb_vop_lookup(*xattrdirvpp, solaris_stream_name, vpp, 14005772Sas200622 name, flags, rootvp, cr)) != 0) { 14015331Samw VN_RELE(*xattrdirvpp); 14025331Samw } else { 14035331Samw (void) strlcpy(od_name, &(name[SMB_STREAM_PREFIX_LEN]), 14045331Samw MAXNAMELEN); 14055331Samw } 14065331Samw 14075331Samw kmem_free(solaris_stream_name, MAXNAMELEN); 14085331Samw kmem_free(name, MAXNAMELEN); 14095331Samw 14105331Samw return (error); 14115331Samw } 14125331Samw 14135331Samw int 14145331Samw smb_vop_stream_create(vnode_t *fvp, char *stream_name, smb_attr_t *attr, 14155772Sas200622 vnode_t **vpp, vnode_t **xattrdirvpp, int flags, cred_t *cr) 14165331Samw { 14175331Samw char *solaris_stream_name; 14185331Samw int error; 14195331Samw 14205331Samw if ((error = smb_vop_lookup_xattrdir(fvp, xattrdirvpp, 14215772Sas200622 LOOKUP_XATTR | CREATE_XATTR_DIR, cr)) != 0) 14225331Samw return (error); 14235331Samw 14245331Samw /* 14255331Samw * Prepend SMB_STREAM_PREFIX to stream name 14265331Samw */ 14275331Samw 14285331Samw solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 14295331Samw (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX, 14305331Samw stream_name); 14315331Samw 14325331Samw if ((error = smb_vop_create(*xattrdirvpp, solaris_stream_name, attr, 14335772Sas200622 vpp, flags, cr, NULL)) != 0) 14345331Samw VN_RELE(*xattrdirvpp); 14355331Samw 14365331Samw kmem_free(solaris_stream_name, MAXNAMELEN); 14375331Samw 14385331Samw return (error); 14395331Samw } 14405331Samw 14415331Samw int 14425772Sas200622 smb_vop_stream_remove(vnode_t *vp, char *stream_name, int flags, cred_t *cr) 14435331Samw { 14445331Samw char *solaris_stream_name; 14455331Samw vnode_t *xattrdirvp; 14465331Samw int error; 14475331Samw 14485772Sas200622 if ((error = smb_vop_lookup_xattrdir(vp, &xattrdirvp, LOOKUP_XATTR, cr)) 14495772Sas200622 != 0) 14505331Samw return (error); 14515331Samw 14525331Samw /* 14535331Samw * Prepend SMB_STREAM_PREFIX to stream name 14545331Samw */ 14555331Samw 14565331Samw solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 14575331Samw (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX, 14585331Samw stream_name); 14595331Samw 14605331Samw /* XXX might have to use kcred */ 14615772Sas200622 error = smb_vop_remove(xattrdirvp, solaris_stream_name, flags, cr); 14625331Samw 14635331Samw kmem_free(solaris_stream_name, MAXNAMELEN); 14645331Samw 14655331Samw return (error); 14665331Samw } 14675331Samw 14685331Samw /* 14695331Samw * smb_vop_stream_readdir() 14705331Samw * 14715331Samw * Note: stream_info.size is not filled in in this routine. 14725331Samw * It needs to be filled in by the caller due to the parameters for getattr. 14735331Samw * 14745331Samw * stream_info.name is set to the on-disk stream name with the SMB_STREAM_PREFIX 14755331Samw * removed. 14765331Samw */ 14775331Samw 14785331Samw int 14795331Samw smb_vop_stream_readdir(vnode_t *fvp, uint32_t *cookiep, 14805331Samw struct fs_stream_info *stream_info, vnode_t **vpp, vnode_t **xattrdirvpp, 14815772Sas200622 int flags, cred_t *cr) 14825331Samw { 14835331Samw int nsize = MAXNAMELEN-1; 14845331Samw int error = 0; 14855331Samw ino64_t ino; 14865331Samw char *tmp_name; 14875331Samw vnode_t *xattrdirvp; 14885331Samw vnode_t *vp; 14895331Samw 14905331Samw if ((error = smb_vop_lookup_xattrdir(fvp, &xattrdirvp, LOOKUP_XATTR, 14915772Sas200622 cr)) != 0) 14925331Samw return (error); 14935331Samw 14945331Samw bzero(stream_info->name, sizeof (stream_info->name)); 14955331Samw stream_info->size = 0; 14965331Samw 14975331Samw tmp_name = kmem_zalloc(MAXNAMELEN, KM_SLEEP); 14985331Samw 14995331Samw for (;;) { 15005331Samw error = smb_vop_readdir(xattrdirvp, cookiep, tmp_name, &nsize, 15015772Sas200622 &ino, &vp, NULL, flags | SMB_STREAM_RDDIR, cr); 15025331Samw 15035331Samw if (error || (*cookiep == SMB_EOF)) 15045331Samw break; 15055331Samw 15065331Samw if (strncmp(tmp_name, SMB_STREAM_PREFIX, 15075331Samw SMB_STREAM_PREFIX_LEN)) { 15085331Samw VN_RELE(vp); 15095331Samw continue; 15105331Samw } 15115331Samw 15125331Samw tmp_name[nsize] = '\0'; 15135331Samw (void) strlcpy(stream_info->name, 15145331Samw &(tmp_name[SMB_STREAM_PREFIX_LEN]), 15155331Samw sizeof (stream_info->name)); 15165331Samw 15175331Samw nsize -= SMB_STREAM_PREFIX_LEN; 15185331Samw break; 15195331Samw } 15205331Samw 15215331Samw if ((error == 0) && nsize) { 15225331Samw if (vpp) 15235331Samw *vpp = vp; 15245331Samw else 15255331Samw VN_RELE(vp); 15265331Samw 15275331Samw if (xattrdirvpp) 15285331Samw *xattrdirvpp = xattrdirvp; 15295331Samw else 15305331Samw VN_RELE(xattrdirvp); 15315331Samw 15325781Sjc198820 } else { 15335781Sjc198820 VN_RELE(xattrdirvp); 15345331Samw } 15355331Samw 15365331Samw kmem_free(tmp_name, MAXNAMELEN); 15375331Samw 15385331Samw return (error); 15395331Samw } 15405331Samw 15415331Samw int 15425331Samw smb_vop_lookup_xattrdir(vnode_t *fvp, vnode_t **xattrdirvpp, int flags, 15435772Sas200622 cred_t *cr) 15445331Samw { 15455331Samw int error; 15465331Samw 15475772Sas200622 error = VOP_LOOKUP(fvp, "", xattrdirvpp, NULL, flags, NULL, cr, 15485772Sas200622 &smb_ct, NULL, NULL); 15495331Samw return (error); 15505331Samw } 15515331Samw 15525331Samw /* 15535331Samw * smb_vop_traverse_check() 15545331Samw * 15555331Samw * This function checks to see if the passed-in vnode has a file system 15565331Samw * mounted on it. If it does, the mount point is "traversed" and the 15575331Samw * vnode for the root of the file system is returned. 15585331Samw */ 15595331Samw 15605331Samw int 15615331Samw smb_vop_traverse_check(vnode_t **vpp) 15625331Samw { 15635331Samw int error; 15645331Samw 15655331Samw if (vn_mountedvfs(*vpp) == 0) 15665331Samw return (0); 15675331Samw 15685331Samw /* 15695331Samw * traverse() may return a different held vnode, even in the error case. 15705331Samw * If it returns a different vnode, it will have released the original. 15715331Samw */ 15725331Samw 15735331Samw error = traverse(vpp); 15745331Samw 15755331Samw return (error); 15765331Samw } 15775331Samw 15785331Samw int /*ARGSUSED*/ 15795331Samw smb_vop_statfs(vnode_t *vp, struct statvfs64 *statp, cred_t *cr) 15805331Samw { 15815331Samw int error; 15825331Samw 15835331Samw error = VFS_STATVFS(vp->v_vfsp, statp); 15845331Samw 15855331Samw return (error); 15865331Samw } 15875331Samw 15885331Samw /* 15895331Samw * smb_vop_acl_read 15905331Samw * 15915331Samw * Reads the ACL of the specified file into 'aclp'. 15925331Samw * acl_type is the type of ACL which the filesystem supports. 15935331Samw * 15945331Samw * Caller has to free the allocated memory for aclp by calling 15955331Samw * acl_free(). 15965331Samw */ 15975331Samw int 15985331Samw smb_vop_acl_read(vnode_t *vp, acl_t **aclp, int flags, acl_type_t acl_type, 15995772Sas200622 cred_t *cr) 16005331Samw { 16015331Samw int error; 16025331Samw vsecattr_t vsecattr; 16035331Samw 16045331Samw ASSERT(vp); 16055331Samw ASSERT(aclp); 16065331Samw 16075331Samw *aclp = NULL; 16085331Samw bzero(&vsecattr, sizeof (vsecattr_t)); 16095331Samw 16105331Samw switch (acl_type) { 16115331Samw case ACLENT_T: 16125331Samw vsecattr.vsa_mask = VSA_ACL | VSA_ACLCNT | VSA_DFACL | 16135331Samw VSA_DFACLCNT; 16145331Samw break; 16155331Samw 16165331Samw case ACE_T: 16175331Samw vsecattr.vsa_mask = VSA_ACE | VSA_ACECNT | VSA_ACE_ACLFLAGS; 16185331Samw break; 16195331Samw 16205331Samw default: 16215331Samw return (EINVAL); 16225331Samw } 16235331Samw 16245772Sas200622 if (error = VOP_GETSECATTR(vp, &vsecattr, flags, cr, &smb_ct)) 16255331Samw return (error); 16265331Samw 16275521Sas200622 *aclp = smb_fsacl_from_vsa(&vsecattr, acl_type); 16285331Samw if (vp->v_type == VDIR) 16295331Samw (*aclp)->acl_flags |= ACL_IS_DIR; 16305331Samw 16315331Samw return (0); 16325331Samw } 16335331Samw 16345331Samw /* 16355331Samw * smb_vop_acl_write 16365331Samw * 16375331Samw * Writes the given ACL in aclp for the specified file. 16385331Samw */ 16395331Samw int 16405772Sas200622 smb_vop_acl_write(vnode_t *vp, acl_t *aclp, int flags, cred_t *cr) 16415331Samw { 16425331Samw int error; 16435331Samw vsecattr_t vsecattr; 16445331Samw int aclbsize; 16455331Samw 16465331Samw ASSERT(vp); 16475331Samw ASSERT(aclp); 16485331Samw 16495521Sas200622 error = smb_fsacl_to_vsa(aclp, &vsecattr, &aclbsize); 16505331Samw 16515331Samw if (error == 0) { 16525331Samw (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); 16535772Sas200622 error = VOP_SETSECATTR(vp, &vsecattr, flags, cr, &smb_ct); 16545331Samw VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 16555331Samw } 16565331Samw 16575331Samw if (aclbsize && vsecattr.vsa_aclentp) 16585331Samw kmem_free(vsecattr.vsa_aclentp, aclbsize); 16595331Samw 16605331Samw return (error); 16615331Samw } 16625331Samw 16635331Samw /* 16645331Samw * smb_vop_acl_type 16655331Samw * 16665331Samw * Determines the ACL type for the given vnode. 16675331Samw * ACLENT_T is a Posix ACL and ACE_T is a ZFS ACL. 16685331Samw */ 16695331Samw acl_type_t 16705331Samw smb_vop_acl_type(vnode_t *vp) 16715331Samw { 16725331Samw int error; 16735331Samw ulong_t whichacl; 16745331Samw 16755331Samw error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &whichacl, kcred, NULL); 16765331Samw if (error != 0) { 16775331Samw /* 16785331Samw * If we got an error, then the filesystem 16795331Samw * likely does not understand the _PC_ACL_ENABLED 16805331Samw * pathconf. In this case, we fall back to trying 16815331Samw * POSIX-draft (aka UFS-style) ACLs. 16825331Samw */ 16835331Samw whichacl = _ACL_ACLENT_ENABLED; 16845331Samw } 16855331Samw 16865331Samw if (!(whichacl & (_ACL_ACE_ENABLED | _ACL_ACLENT_ENABLED))) { 16875331Samw /* 16885331Samw * If the file system supports neither ACE nor 16895331Samw * ACLENT ACLs we will fall back to UFS-style ACLs 16905331Samw * like we did above if there was an error upon 16915331Samw * calling VOP_PATHCONF. 16925331Samw * 16935331Samw * ACE and ACLENT type ACLs are the only interfaces 16945331Samw * supported thus far. If any other bits are set on 16955331Samw * 'whichacl' upon return from VOP_PATHCONF, we will 16965331Samw * ignore them. 16975331Samw */ 16985331Samw whichacl = _ACL_ACLENT_ENABLED; 16995331Samw } 17005331Samw 17015331Samw if (whichacl == _ACL_ACLENT_ENABLED) 17025331Samw return (ACLENT_T); 17035331Samw 17045331Samw return (ACE_T); 17055331Samw } 17065331Samw 17075331Samw static int zfs_perms[] = { 17085331Samw ACE_READ_DATA, ACE_WRITE_DATA, ACE_APPEND_DATA, ACE_READ_NAMED_ATTRS, 17095331Samw ACE_WRITE_NAMED_ATTRS, ACE_EXECUTE, ACE_DELETE_CHILD, 17105331Samw ACE_READ_ATTRIBUTES, ACE_WRITE_ATTRIBUTES, ACE_DELETE, ACE_READ_ACL, 17115331Samw ACE_WRITE_ACL, ACE_WRITE_OWNER, ACE_SYNCHRONIZE 17125331Samw }; 17135331Samw 17145331Samw static int unix_perms[] = { VREAD, VWRITE, VEXEC }; 17155331Samw /* 17165331Samw * smb_vop_eaccess 17175331Samw * 17185331Samw * Returns the effective permission of the given credential for the 17195331Samw * specified object. 17205331Samw * 17215331Samw * This is just a workaround. We need VFS/FS support for this. 17225331Samw */ 17235331Samw void 17245331Samw smb_vop_eaccess(vnode_t *vp, int *mode, int flags, vnode_t *dir_vp, cred_t *cr) 17255331Samw { 17265331Samw int error, i; 17275331Samw int pnum; 17285331Samw 17295331Samw *mode = 0; 17305331Samw 17315331Samw if (flags == V_ACE_MASK) { 17325331Samw pnum = sizeof (zfs_perms) / sizeof (int); 17335331Samw 17345331Samw for (i = 0; i < pnum; i++) { 17355331Samw error = smb_vop_access(vp, zfs_perms[i], flags, 17365331Samw dir_vp, cr); 17375331Samw if (error == 0) 17385331Samw *mode |= zfs_perms[i]; 17395331Samw } 17405331Samw } else { 17415331Samw pnum = sizeof (unix_perms) / sizeof (int); 17425331Samw 17435331Samw for (i = 0; i < pnum; i++) { 17445331Samw error = smb_vop_access(vp, unix_perms[i], flags, 17455331Samw dir_vp, cr); 17465331Samw if (error == 0) 17475331Samw *mode |= unix_perms[i]; 17485331Samw } 17495331Samw } 17505331Samw } 17515772Sas200622 17525772Sas200622 /* 17535772Sas200622 * smb_vop_shrlock() 17545772Sas200622 * 17555772Sas200622 * See comments for smb_fsop_shrlock() 17565772Sas200622 */ 17575772Sas200622 17585772Sas200622 int 17595772Sas200622 smb_vop_shrlock(vnode_t *vp, uint32_t uniq_fid, uint32_t desired_access, 17605772Sas200622 uint32_t share_access, cred_t *cr) 17615772Sas200622 { 17625772Sas200622 struct shrlock shr; 17635772Sas200622 struct shr_locowner shr_own; 17645772Sas200622 short new_access = 0; 17655772Sas200622 short deny = 0; 17665772Sas200622 int flag = 0; 17675772Sas200622 int cmd; 17685772Sas200622 17695772Sas200622 cmd = (nbl_need_check(vp)) ? F_SHARE_NBMAND : F_SHARE; 17705772Sas200622 17715772Sas200622 /* 17725772Sas200622 * Check if this is a metadata access 17735772Sas200622 */ 17745772Sas200622 17755772Sas200622 if ((desired_access & FILE_DATA_ALL) == 0) { 17765772Sas200622 new_access |= F_MDACC; 17775772Sas200622 } else { 17785772Sas200622 if (desired_access & (ACE_READ_DATA | ACE_EXECUTE)) { 17795772Sas200622 new_access |= F_RDACC; 17805772Sas200622 flag |= FREAD; 17815772Sas200622 } 17825772Sas200622 17835772Sas200622 if (desired_access & (ACE_WRITE_DATA | ACE_APPEND_DATA | 17845772Sas200622 ACE_ADD_FILE)) { 17855772Sas200622 new_access |= F_WRACC; 17865772Sas200622 flag |= FWRITE; 17875772Sas200622 } 17885772Sas200622 17895772Sas200622 if (SMB_DENY_READ(share_access)) { 17905772Sas200622 deny |= F_RDDNY; 17915772Sas200622 } 17925772Sas200622 17935772Sas200622 if (SMB_DENY_WRITE(share_access)) { 17945772Sas200622 deny |= F_WRDNY; 17955772Sas200622 } 17965772Sas200622 17975772Sas200622 if (cmd == F_SHARE_NBMAND) { 17985772Sas200622 if (desired_access & ACE_DELETE) 17995772Sas200622 new_access |= F_RMACC; 18005772Sas200622 18015772Sas200622 if (SMB_DENY_DELETE(share_access)) { 18025772Sas200622 deny |= F_RMDNY; 18035772Sas200622 } 18045772Sas200622 } 18055772Sas200622 } 18065772Sas200622 18075772Sas200622 shr.s_access = new_access; 18085772Sas200622 shr.s_deny = deny; 18095772Sas200622 shr.s_sysid = smb_ct.cc_sysid; 18105772Sas200622 shr.s_pid = uniq_fid; 18115772Sas200622 shr.s_own_len = sizeof (shr_own); 18125772Sas200622 shr.s_owner = (caddr_t)&shr_own; 18135772Sas200622 shr_own.sl_id = shr.s_sysid; 18145772Sas200622 shr_own.sl_pid = shr.s_pid; 18155772Sas200622 18165772Sas200622 return (VOP_SHRLOCK(vp, cmd, &shr, flag, cr, NULL)); 18175772Sas200622 } 18185772Sas200622 18195772Sas200622 int 18205772Sas200622 smb_vop_unshrlock(vnode_t *vp, uint32_t uniq_fid, cred_t *cr) 18215772Sas200622 { 18225772Sas200622 struct shrlock shr; 18235772Sas200622 struct shr_locowner shr_own; 18245772Sas200622 18255772Sas200622 /* 18265772Sas200622 * For s_access and s_deny, we do not need to pass in the original 18275772Sas200622 * values. 18285772Sas200622 */ 18295772Sas200622 18305772Sas200622 shr.s_access = 0; 18315772Sas200622 shr.s_deny = 0; 18325772Sas200622 shr.s_sysid = smb_ct.cc_sysid; 18335772Sas200622 shr.s_pid = uniq_fid; 18345772Sas200622 shr.s_own_len = sizeof (shr_own); 18355772Sas200622 shr.s_owner = (caddr_t)&shr_own; 18365772Sas200622 shr_own.sl_id = shr.s_sysid; 18375772Sas200622 shr_own.sl_pid = shr.s_pid; 18385772Sas200622 18395772Sas200622 return (VOP_SHRLOCK(vp, F_UNSHARE, &shr, 0, cr, NULL)); 18405772Sas200622 } 1841