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> 406139Sjb150015 #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*7052Samw smb_vop_readdir_readpage(vnode_t *, void *, uint32_t, int *, cred_t *); 555331Samw 565331Samw static int 576139Sjb150015 smb_vop_readdir_entry(vnode_t *, uint32_t *, char *, int *, 586139Sjb150015 ino64_t *, vnode_t **, char *, int, cred_t *, char *, int); 595331Samw 605331Samw static int 616139Sjb150015 smb_vop_getdents_entries(smb_node_t *, uint32_t *, int32_t *, char *, uint32_t, 626139Sjb150015 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 736600Sas200622 static 746600Sas200622 callb_cpr_t *smb_lock_frlock_callback(flk_cb_when_t, void *); 756600Sas200622 765772Sas200622 extern sysid_t lm_alloc_sysidt(); 775772Sas200622 785331Samw #define SMB_AT_MAX 16 795331Samw static uint_t smb_attrmap[SMB_AT_MAX] = { 805331Samw 0, 815331Samw AT_TYPE, 825331Samw AT_MODE, 835331Samw AT_UID, 845331Samw AT_GID, 855331Samw AT_FSID, 865331Samw AT_NODEID, 875331Samw AT_NLINK, 885331Samw AT_SIZE, 895331Samw AT_ATIME, 905331Samw AT_MTIME, 915331Samw AT_CTIME, 925331Samw AT_RDEV, 935331Samw AT_BLKSIZE, 945331Samw AT_NBLOCKS, 955331Samw AT_SEQ 965331Samw }; 975331Samw 986139Sjb150015 static boolean_t smb_vop_initialized = B_FALSE; 996139Sjb150015 caller_context_t smb_ct; 1006139Sjb150015 1016139Sjb150015 /* 1026139Sjb150015 * smb_vop_init 1036139Sjb150015 * 1046139Sjb150015 * This function is not multi-thread safe. The caller must make sure only one 1056139Sjb150015 * thread makes the call. 1066139Sjb150015 */ 1076139Sjb150015 int 1086139Sjb150015 smb_vop_init(void) 1096139Sjb150015 { 1106139Sjb150015 if (smb_vop_initialized) 1116139Sjb150015 return (0); 1126139Sjb150015 /* 1136139Sjb150015 * The caller_context will be used primarily for range locking. 1146139Sjb150015 * Since the CIFS server is mapping its locks to POSIX locks, 1156139Sjb150015 * only one pid is used for operations originating from the 1166139Sjb150015 * CIFS server (to represent CIFS in the VOP_FRLOCK routines). 1176139Sjb150015 */ 1186139Sjb150015 smb_ct.cc_sysid = lm_alloc_sysidt(); 1196139Sjb150015 if (smb_ct.cc_sysid == LM_NOSYSID) 1206139Sjb150015 return (ENOMEM); 1216139Sjb150015 1226139Sjb150015 smb_ct.cc_caller_id = fs_new_caller_id(); 1236432Sas200622 smb_ct.cc_pid = IGN_PID; 1246139Sjb150015 smb_ct.cc_flags = 0; 1256139Sjb150015 1266139Sjb150015 smb_vop_initialized = B_TRUE; 1276139Sjb150015 return (0); 1286139Sjb150015 } 1296139Sjb150015 1306139Sjb150015 /* 1316139Sjb150015 * smb_vop_fini 1326139Sjb150015 * 1336139Sjb150015 * This function is not multi-thread safe. The caller must make sure only one 1346139Sjb150015 * thread makes the call. 1356139Sjb150015 */ 1366139Sjb150015 void 1376139Sjb150015 smb_vop_fini(void) 1386139Sjb150015 { 1396139Sjb150015 if (!smb_vop_initialized) 1406139Sjb150015 return; 1416139Sjb150015 1426139Sjb150015 lm_free_sysidt(smb_ct.cc_sysid); 1436432Sas200622 smb_ct.cc_pid = IGN_PID; 1446139Sjb150015 smb_ct.cc_sysid = LM_NOSYSID; 1456139Sjb150015 smb_vop_initialized = B_FALSE; 1466139Sjb150015 } 1476139Sjb150015 1485772Sas200622 /* 1495772Sas200622 * The smb_ct will be used primarily for range locking. 1505772Sas200622 * Since the CIFS server is mapping its locks to POSIX locks, 1515772Sas200622 * only one pid is used for operations originating from the 1525772Sas200622 * CIFS server (to represent CIFS in the VOP_FRLOCK routines). 1535772Sas200622 */ 1545772Sas200622 1555331Samw int 1565772Sas200622 smb_vop_open(vnode_t **vpp, int mode, cred_t *cred) 1575331Samw { 1585772Sas200622 return (VOP_OPEN(vpp, mode, cred, &smb_ct)); 1595772Sas200622 } 1605772Sas200622 1615772Sas200622 int 1625772Sas200622 smb_vop_close(vnode_t *vp, int mode, cred_t *cred) 1635772Sas200622 { 1645772Sas200622 return (VOP_CLOSE(vp, mode, 1, (offset_t)0, cred, &smb_ct)); 1655331Samw } 1665331Samw 1676600Sas200622 int 1686600Sas200622 smb_vop_other_opens(vnode_t *vp, int mode) 1696600Sas200622 { 1706600Sas200622 return (((mode & FWRITE) && vn_has_other_opens(vp, V_WRITE)) || 1716600Sas200622 (((mode & FWRITE) == 0) && vn_is_opened(vp, V_WRITE)) || 1726600Sas200622 ((mode & FREAD) && vn_has_other_opens(vp, V_READ)) || 1736600Sas200622 (((mode & FREAD) == 0) && vn_is_opened(vp, V_READ)) || 1746600Sas200622 vn_is_mapped(vp, V_RDORWR)); 1756600Sas200622 } 1766600Sas200622 1775331Samw /* 1785331Samw * The smb_vop_* functions have minimal knowledge of CIFS semantics and 1795331Samw * serve as an interface to the VFS layer. 1805331Samw * 1815331Samw * Only smb_fsop_* layer functions should call smb_vop_* layer functions. 1825331Samw * (Higher-level CIFS service code should never skip the smb_fsop_* layer 1835331Samw * to call smb_vop_* layer functions directly.) 1845331Samw */ 1855331Samw 1865331Samw /* 1875331Samw * XXX - Extended attributes support in the file system assumed. 1885331Samw * This is needed for full NT Streams functionality. 1895331Samw */ 1905331Samw 1915331Samw int 1925772Sas200622 smb_vop_read(vnode_t *vp, uio_t *uiop, cred_t *cr) 1935331Samw { 1945331Samw int error; 1955331Samw 1966600Sas200622 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &smb_ct); 1975772Sas200622 error = VOP_READ(vp, uiop, 0, cr, &smb_ct); 1986600Sas200622 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &smb_ct); 1995331Samw return (error); 2005331Samw } 2015331Samw 2025331Samw int 203*7052Samw smb_vop_write(vnode_t *vp, uio_t *uiop, int ioflag, uint32_t *lcount, 2045772Sas200622 cred_t *cr) 2055331Samw { 2065331Samw int error; 2075331Samw 2085331Samw *lcount = uiop->uio_resid; 2095331Samw 2105331Samw uiop->uio_llimit = MAXOFFSET_T; 2115331Samw 2126600Sas200622 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &smb_ct); 2135772Sas200622 error = VOP_WRITE(vp, uiop, ioflag, cr, &smb_ct); 2146600Sas200622 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &smb_ct); 2155331Samw 2165331Samw *lcount -= uiop->uio_resid; 2175331Samw 2185331Samw return (error); 2195331Samw } 2205331Samw 2215331Samw /* 2225331Samw * smb_vop_getattr() 2235331Samw * 2245331Samw * smb_fsop_getattr()/smb_vop_getattr() should always be called from the CIFS 2255331Samw * service (instead of calling VOP_GETATTR directly) to retrieve attributes 2265331Samw * due to special processing needed for streams files. 2275331Samw * 2285331Samw * All attributes are retrieved. 2295331Samw * 2305331Samw * A named stream's attributes (as far as CIFS is concerned) are those of the 2315331Samw * unnamed (i.e. data) stream (minus the size attribute), and the size of the 2325331Samw * named stream. Though the file system may store attributes other than size 2335331Samw * with the named stream, these should not be used by CIFS for any purpose. 2345331Samw * 2355331Samw * When vp denotes a named stream, then unnamed_vp should be passed in (denoting 2365331Samw * the corresponding unnamed stream). 2375331Samw */ 2385331Samw 2395331Samw int 2405331Samw smb_vop_getattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *ret_attr, 2415772Sas200622 int flags, cred_t *cr) 2425331Samw { 2435331Samw int error; 2445331Samw vnode_t *use_vp; 2455331Samw smb_attr_t tmp_attr; 2465331Samw xvattr_t tmp_xvattr; 2475331Samw xoptattr_t *xoap = NULL; 2485331Samw 2495331Samw if (unnamed_vp) 2505331Samw use_vp = unnamed_vp; 2515331Samw else 2525331Samw use_vp = vp; 2535331Samw 2545331Samw if (vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) { 2555331Samw xva_init(&tmp_xvattr); 2565331Samw xoap = xva_getxoptattr(&tmp_xvattr); 2575331Samw 2585331Samw ASSERT(xoap); 2595331Samw 2605331Samw smb_sa_to_va_mask(ret_attr->sa_mask, 2615331Samw &tmp_xvattr.xva_vattr.va_mask); 2625331Samw 2635331Samw XVA_SET_REQ(&tmp_xvattr, XAT_READONLY); 2645331Samw XVA_SET_REQ(&tmp_xvattr, XAT_HIDDEN); 2655331Samw XVA_SET_REQ(&tmp_xvattr, XAT_SYSTEM); 2665331Samw XVA_SET_REQ(&tmp_xvattr, XAT_ARCHIVE); 2675331Samw XVA_SET_REQ(&tmp_xvattr, XAT_CREATETIME); 2685331Samw 2695331Samw if ((error = VOP_GETATTR(use_vp, (vattr_t *)&tmp_xvattr, flags, 2705772Sas200622 cr, &smb_ct)) != 0) 2715331Samw return (error); 2725331Samw 2735331Samw ret_attr->sa_vattr = tmp_xvattr.xva_vattr; 2745331Samw 2755331Samw /* 2765331Samw * Copy special attributes to ret_attr parameter 2775331Samw */ 2785331Samw 2795331Samw ret_attr->sa_dosattr = 0; 2805331Samw 2815331Samw ASSERT(tmp_xvattr.xva_vattr.va_mask & AT_XVATTR); 2825331Samw 2835331Samw xoap = xva_getxoptattr(&tmp_xvattr); 2845331Samw ASSERT(xoap); 2855331Samw 2865331Samw if (XVA_ISSET_RTN(&tmp_xvattr, XAT_READONLY)) { 2875331Samw if (xoap->xoa_readonly) 2885331Samw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_READONLY; 2895331Samw } 2905331Samw 2915331Samw if (XVA_ISSET_RTN(&tmp_xvattr, XAT_HIDDEN)) { 2925331Samw if (xoap->xoa_hidden) 2935331Samw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_HIDDEN; 2945331Samw } 2955331Samw 2965331Samw if (XVA_ISSET_RTN(&tmp_xvattr, XAT_SYSTEM)) { 2975331Samw if (xoap->xoa_system) 2985331Samw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_SYSTEM; 2995331Samw } 3005331Samw 3015331Samw if (XVA_ISSET_RTN(&tmp_xvattr, XAT_ARCHIVE)) { 3025331Samw if (xoap->xoa_archive) 3035331Samw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_ARCHIVE; 3045331Samw } 3055331Samw 3065331Samw ret_attr->sa_crtime = xoap->xoa_createtime; 3075331Samw 3085331Samw if (unnamed_vp && (ret_attr->sa_mask & SMB_AT_SIZE)) { 3095331Samw /* 3105331Samw * Retrieve stream size attribute into temporary 3115331Samw * structure, in case the underlying file system 3125331Samw * returns attributes other than the size (we do not 3135331Samw * want to have ret_attr's other fields get 3145331Samw * overwritten). 3155331Samw * 3165331Samw * Note that vp is used here, and not use_vp. 3175331Samw * Also, only AT_SIZE is needed. 3185331Samw */ 3195331Samw 3205331Samw tmp_xvattr.xva_vattr.va_mask = AT_SIZE; 3215331Samw 3225331Samw if ((error = VOP_GETATTR(vp, (vattr_t *)&tmp_xvattr, 3235772Sas200622 flags, cr, &smb_ct)) != 0) 3245331Samw return (error); 3255331Samw 3265331Samw ret_attr->sa_vattr.va_size = 3275331Samw tmp_xvattr.xva_vattr.va_size; 3285331Samw 3295331Samw } 3305331Samw 3315331Samw if (ret_attr->sa_vattr.va_type == VDIR) { 3325331Samw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY; 3335331Samw } 3345331Samw 3355331Samw return (error); 3365331Samw } 3375331Samw 3385331Samw /* 3395331Samw * Support for file systems without VFSFT_XVATTR 3405331Samw */ 3415331Samw 3425331Samw smb_sa_to_va_mask(ret_attr->sa_mask, 3435331Samw &ret_attr->sa_vattr.va_mask); 3445331Samw 3455772Sas200622 error = VOP_GETATTR(use_vp, &ret_attr->sa_vattr, flags, cr, &smb_ct); 3465331Samw 3475331Samw if (error != 0) 3485331Samw return (error); 3495331Samw 3505331Samw /* 3515331Samw * "Fake" DOS attributes and create time, filesystem doesn't support 3525331Samw * them. 3535331Samw */ 3545331Samw 3555331Samw ret_attr->sa_dosattr = 0; 3565331Samw ret_attr->sa_crtime = ret_attr->sa_vattr.va_ctime; 3575331Samw 3585331Samw if (unnamed_vp && (ret_attr->sa_mask & SMB_AT_SIZE)) { 3595331Samw /* 3605331Samw * Retrieve stream size attribute into temporary structure, 3615331Samw * in case the underlying file system returns attributes 3625331Samw * other than the size (we do not want to have ret_attr's 3635331Samw * other fields get overwritten). 3645331Samw * 3655331Samw * Note that vp is used here, and not use_vp. 3665331Samw * Also, only AT_SIZE is needed. 3675331Samw */ 3685331Samw 3695331Samw tmp_attr.sa_vattr.va_mask = AT_SIZE; 3705772Sas200622 error = VOP_GETATTR(vp, &tmp_attr.sa_vattr, flags, cr, &smb_ct); 3715331Samw 3725331Samw if (error != 0) 3735331Samw return (error); 3745331Samw 3755331Samw 3765331Samw ret_attr->sa_vattr.va_size = tmp_attr.sa_vattr.va_size; 3775331Samw } 3785331Samw 3795331Samw if (ret_attr->sa_vattr.va_type == VDIR) { 3805331Samw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY; 3815331Samw } 3825331Samw 3835331Samw return (error); 3845331Samw } 3855331Samw 3865331Samw /* 3875331Samw * smb_vop_setattr() 3885331Samw * 3896030Sjb150015 * smb_fsop_setattr()/smb_vop_setattr() should always be used instead of 3906030Sjb150015 * VOP_SETATTR() when calling from the CIFS service, due to special processing 3916030Sjb150015 * for streams files. 3925331Samw * 3936030Sjb150015 * Streams have a size but otherwise do not have separate attributes from 3946030Sjb150015 * the (unnamed stream) file, i.e., the security and ownership of the file 3956030Sjb150015 * applies to the stream. In contrast, extended attribute files, which are 3966030Sjb150015 * used to implement streams, are independent objects with their own 3976030Sjb150015 * attributes. 3986030Sjb150015 * 3996030Sjb150015 * For compatibility with streams, we set the size on the extended attribute 4006030Sjb150015 * file and apply other attributes to the (unnamed stream) file. The one 4016030Sjb150015 * exception is that the UID and GID can be set on the stream by passing a 4026030Sjb150015 * NULL unnamed_vp, which allows callers to synchronize stream ownership 4036030Sjb150015 * with the (unnamed stream) file. 4045331Samw */ 4055331Samw 4065331Samw int 4075331Samw smb_vop_setattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *set_attr, 4085772Sas200622 int flags, cred_t *cr, boolean_t no_xvattr) 4095331Samw { 4105331Samw int error = 0; 4115331Samw int at_size = 0; 4125331Samw vnode_t *use_vp; 4135772Sas200622 xvattr_t xvattr; 4145772Sas200622 vattr_t *vap; 4155331Samw 4165331Samw if (unnamed_vp) { 4175331Samw use_vp = unnamed_vp; 4185331Samw if (set_attr->sa_mask & SMB_AT_SIZE) { 4195331Samw at_size = 1; 4205331Samw set_attr->sa_mask &= ~SMB_AT_SIZE; 4215331Samw } 4225331Samw } else { 4235331Samw use_vp = vp; 4245331Samw } 4255331Samw 4265331Samw /* 4275331Samw * The caller should not be setting sa_vattr.va_mask, 4285331Samw * but rather sa_mask. 4295331Samw */ 4305331Samw 4315331Samw set_attr->sa_vattr.va_mask = 0; 4325331Samw 4335521Sas200622 if ((no_xvattr == B_FALSE) && 4345521Sas200622 vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) { 4355331Samw 4365772Sas200622 smb_vop_setup_xvattr(set_attr, &xvattr); 4375772Sas200622 vap = (vattr_t *)&xvattr; 4385772Sas200622 } else { 4395331Samw smb_sa_to_va_mask(set_attr->sa_mask, 4405772Sas200622 &set_attr->sa_vattr.va_mask); 4415772Sas200622 vap = &set_attr->sa_vattr; 4425772Sas200622 } 4435331Samw 4445772Sas200622 if ((error = VOP_SETATTR(use_vp, vap, flags, cr, &smb_ct)) != 0) 4455772Sas200622 return (error); 4465331Samw 4475331Samw /* 4485772Sas200622 * If the size of the stream needs to be set, set it on 4495772Sas200622 * the stream file directly. (All other indicated attributes 4506030Sjb150015 * are set on the stream's unnamed stream, except under the 4516030Sjb150015 * exception described in the function header.) 4525331Samw */ 4535331Samw 4545331Samw if (at_size) { 4555331Samw /* 4565331Samw * set_attr->sa_vattr.va_size already contains the 4575331Samw * size as set by the caller 4585331Samw * 4595331Samw * Note that vp is used here, and not use_vp. 4605331Samw * Also, only AT_SIZE is needed. 4615331Samw */ 4625331Samw 4635331Samw set_attr->sa_vattr.va_mask = AT_SIZE; 4645772Sas200622 error = VOP_SETATTR(vp, &set_attr->sa_vattr, flags, cr, 4655772Sas200622 &smb_ct); 4665331Samw } 4675772Sas200622 4685331Samw return (error); 4695331Samw } 4705331Samw 4715331Samw /* 4725331Samw * smb_vop_access 4735331Samw * 4745331Samw * This is a wrapper round VOP_ACCESS. VOP_ACCESS checks the given mode 4755331Samw * against file's ACL or Unix permissions. CIFS on the other hand needs to 4765331Samw * know if the requested operation can succeed for the given object, this 4775331Samw * requires more checks in case of DELETE bit since permissions on the parent 4785331Samw * directory are important as well. Based on Windows rules if parent's ACL 4795331Samw * grant FILE_DELETE_CHILD a file can be delete regardless of the file's 4805331Samw * permissions. 4815331Samw */ 4825331Samw int 4835331Samw smb_vop_access(vnode_t *vp, int mode, int flags, vnode_t *dir_vp, cred_t *cr) 4845331Samw { 4855331Samw int error = 0; 4865331Samw 4875331Samw if (mode == 0) 4885331Samw return (0); 4895331Samw 4905331Samw if ((flags == V_ACE_MASK) && (mode & ACE_DELETE)) { 4915331Samw if (dir_vp) { 4925331Samw error = VOP_ACCESS(dir_vp, ACE_DELETE_CHILD, flags, 4935331Samw cr, NULL); 4945331Samw 4955331Samw if (error == 0) 4965331Samw mode &= ~ACE_DELETE; 4975331Samw } 4985331Samw } 4995331Samw 5005331Samw if (mode) { 5015331Samw error = VOP_ACCESS(vp, mode, flags, cr, NULL); 5025331Samw } 5035331Samw 5045331Samw return (error); 5055331Samw } 5065331Samw 5075331Samw /* 5085331Samw * smb_vop_lookup 5095331Samw * 5105331Samw * dvp: directory vnode (in) 5115331Samw * name: name of file to be looked up (in) 5125331Samw * vpp: looked-up vnode (out) 5135331Samw * od_name: on-disk name of file (out). 5145331Samw * This parameter is optional. If a pointer is passed in, it 5155331Samw * must be allocated with MAXNAMELEN bytes 5165331Samw * rootvp: vnode of the tree root (in) 5175331Samw * This parameter is always passed in non-NULL except at the time 5185331Samw * of share set up. 5195331Samw */ 5205331Samw 5215331Samw int 5226139Sjb150015 smb_vop_lookup( 5236139Sjb150015 vnode_t *dvp, 5246139Sjb150015 char *name, 5256139Sjb150015 vnode_t **vpp, 5266139Sjb150015 char *od_name, 5276139Sjb150015 int flags, 5286139Sjb150015 vnode_t *rootvp, 5296139Sjb150015 cred_t *cr) 5305331Samw { 5315331Samw int error = 0; 5325331Samw int option_flags = 0; 5335331Samw pathname_t rpn; 5345331Samw 5355331Samw if (*name == '\0') 5365331Samw return (EINVAL); 5375331Samw 5385331Samw ASSERT(vpp); 5395331Samw *vpp = NULL; 5405331Samw 5415331Samw if ((name[0] == '.') && (name[1] == '.') && (name[2] == 0)) { 5425331Samw if (rootvp && (dvp == rootvp)) { 5435331Samw VN_HOLD(dvp); 5445331Samw *vpp = dvp; 5455331Samw return (0); 5465331Samw } 5475331Samw 5485331Samw if (dvp->v_flag & VROOT) { 5495331Samw vfs_t *vfsp; 5505331Samw vnode_t *cvp = dvp; 5515331Samw 5525331Samw /* 5535331Samw * Set dvp and check for races with forced unmount 5545331Samw * (see lookuppnvp()) 5555331Samw */ 5565331Samw 5575331Samw vfsp = cvp->v_vfsp; 5585331Samw vfs_rlock_wait(vfsp); 5595331Samw if (((dvp = cvp->v_vfsp->vfs_vnodecovered) == NULL) || 5605331Samw (cvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)) { 5615331Samw vfs_unlock(vfsp); 5625331Samw return (EIO); 5635331Samw } 5645331Samw vfs_unlock(vfsp); 5655331Samw } 5665331Samw } 5675331Samw 5685331Samw 5695331Samw 5705331Samw if (flags & SMB_IGNORE_CASE) 5715331Samw option_flags = FIGNORECASE; 5725331Samw 5735331Samw pn_alloc(&rpn); 5745331Samw 5755331Samw error = VOP_LOOKUP(dvp, name, vpp, NULL, option_flags, NULL, cr, 5765772Sas200622 &smb_ct, NULL, &rpn); 5775331Samw 5785331Samw if ((error == 0) && od_name) { 5795331Samw bzero(od_name, MAXNAMELEN); 5805331Samw if (option_flags == FIGNORECASE) 5815331Samw (void) strlcpy(od_name, rpn.pn_buf, MAXNAMELEN); 5825331Samw else 5835331Samw (void) strlcpy(od_name, name, MAXNAMELEN); 5845331Samw } 5855331Samw 5865331Samw pn_free(&rpn); 5875331Samw return (error); 5885331Samw } 5895331Samw 5905331Samw int 5915331Samw smb_vop_create(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp, 5925772Sas200622 int flags, cred_t *cr, vsecattr_t *vsap) 5935772Sas200622 { 5945772Sas200622 int error; 5955772Sas200622 int option_flags = 0; 5965772Sas200622 xvattr_t xvattr; 5975772Sas200622 vattr_t *vap; 5985772Sas200622 5995772Sas200622 if (flags & SMB_IGNORE_CASE) 6005772Sas200622 option_flags = FIGNORECASE; 6015772Sas200622 6025772Sas200622 attr->sa_vattr.va_mask = 0; 6035772Sas200622 6045772Sas200622 if (vfs_has_feature(dvp->v_vfsp, VFSFT_XVATTR)) { 6055772Sas200622 smb_vop_setup_xvattr(attr, &xvattr); 6065772Sas200622 vap = (vattr_t *)&xvattr; 6075772Sas200622 } else { 6085772Sas200622 smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask); 6095772Sas200622 vap = &attr->sa_vattr; 6105772Sas200622 } 6115772Sas200622 6125772Sas200622 error = VOP_CREATE(dvp, name, vap, EXCL, attr->sa_vattr.va_mode, 6135772Sas200622 vpp, cr, option_flags, &smb_ct, vsap); 6145772Sas200622 6155772Sas200622 return (error); 6165772Sas200622 } 6175772Sas200622 6185772Sas200622 int 6195772Sas200622 smb_vop_remove(vnode_t *dvp, char *name, int flags, cred_t *cr) 6205331Samw { 6215331Samw int error; 6225331Samw int option_flags = 0; 6235331Samw 6245331Samw if (flags & SMB_IGNORE_CASE) 6255331Samw option_flags = FIGNORECASE; 6265331Samw 6275772Sas200622 error = VOP_REMOVE(dvp, name, cr, &smb_ct, option_flags); 6285331Samw 6295331Samw return (error); 6305331Samw } 6315331Samw 6325331Samw /* 6335331Samw * smb_vop_rename() 6345331Samw * 6355331Samw * The rename is for files in the same tree (identical TID) only. 6365331Samw */ 6375331Samw 6385331Samw int 6395331Samw smb_vop_rename(vnode_t *from_dvp, char *from_name, vnode_t *to_dvp, 6405772Sas200622 char *to_name, int flags, cred_t *cr) 6415331Samw { 6425331Samw int error; 6435331Samw int option_flags = 0; 6445331Samw 6455331Samw 6465331Samw if (flags & SMB_IGNORE_CASE) 6475331Samw option_flags = FIGNORECASE; 6485331Samw 6495331Samw error = VOP_RENAME(from_dvp, from_name, to_dvp, to_name, cr, 6505772Sas200622 &smb_ct, option_flags); 6515331Samw 6525331Samw return (error); 6535331Samw } 6545331Samw 6555331Samw int 6565331Samw smb_vop_mkdir(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp, 6575772Sas200622 int flags, cred_t *cr, vsecattr_t *vsap) 6585331Samw { 6595331Samw int error; 6605331Samw int option_flags = 0; 6615331Samw 6625331Samw 6635331Samw 6645331Samw if (flags & SMB_IGNORE_CASE) 6655331Samw option_flags = FIGNORECASE; 6665331Samw 6675331Samw smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask); 6685331Samw 6695772Sas200622 error = VOP_MKDIR(dvp, name, &attr->sa_vattr, vpp, cr, &smb_ct, 6705331Samw option_flags, vsap); 6715331Samw 6725331Samw return (error); 6735331Samw } 6745331Samw 6755331Samw /* 6765331Samw * smb_vop_rmdir() 6775331Samw * 6785331Samw * Only simple rmdir supported, consistent with NT semantics 6795331Samw * (can only remove an empty directory). 6805331Samw * 6815331Samw */ 6825331Samw 6835331Samw int 6845772Sas200622 smb_vop_rmdir(vnode_t *dvp, char *name, int flags, cred_t *cr) 6855331Samw { 6865331Samw int error; 6875331Samw int option_flags = 0; 6885331Samw 6895331Samw if (flags & SMB_IGNORE_CASE) 6905331Samw option_flags = FIGNORECASE; 6915331Samw 6925331Samw /* 6935331Samw * Comments adapted from rfs_rmdir(). 6945331Samw * 6955331Samw * VOP_RMDIR now takes a new third argument (the current 6965331Samw * directory of the process). That's because rmdir 6975331Samw * wants to return EINVAL if one tries to remove ".". 6985331Samw * Of course, SMB servers do not know what their 6995331Samw * clients' current directories are. We fake it by 7005331Samw * supplying a vnode known to exist and illegal to 7015331Samw * remove. 7025331Samw */ 7035331Samw 7045772Sas200622 error = VOP_RMDIR(dvp, name, rootdir, cr, &smb_ct, option_flags); 7055331Samw return (error); 7065331Samw } 7075331Samw 7085331Samw int 7095772Sas200622 smb_vop_commit(vnode_t *vp, cred_t *cr) 7105772Sas200622 { 7115772Sas200622 return (VOP_FSYNC(vp, 1, cr, &smb_ct)); 7125772Sas200622 } 7135772Sas200622 7145772Sas200622 void 7155772Sas200622 smb_vop_setup_xvattr(smb_attr_t *smb_attr, xvattr_t *xvattr) 7165331Samw { 7175772Sas200622 xoptattr_t *xoap = NULL; 7185772Sas200622 uint_t xva_mask; 7195772Sas200622 7205772Sas200622 /* 7215772Sas200622 * Initialize xvattr, including bzero 7225772Sas200622 */ 7235772Sas200622 xva_init(xvattr); 7245772Sas200622 xoap = xva_getxoptattr(xvattr); 7255772Sas200622 7265772Sas200622 ASSERT(xoap); 7275772Sas200622 7285772Sas200622 /* 7295772Sas200622 * Copy caller-specified classic attributes to xvattr. 7305772Sas200622 * First save xvattr's mask (set in xva_init()), which 7315772Sas200622 * contains AT_XVATTR. This is |'d in later if needed. 7325772Sas200622 */ 7335772Sas200622 7345772Sas200622 xva_mask = xvattr->xva_vattr.va_mask; 7355772Sas200622 xvattr->xva_vattr = smb_attr->sa_vattr; 7365772Sas200622 7375772Sas200622 smb_sa_to_va_mask(smb_attr->sa_mask, &xvattr->xva_vattr.va_mask); 7385772Sas200622 7395772Sas200622 /* 7405772Sas200622 * Do not set ctime (only the file system can do it) 7415772Sas200622 */ 7425772Sas200622 7435772Sas200622 xvattr->xva_vattr.va_mask &= ~AT_CTIME; 7445772Sas200622 7455772Sas200622 if (smb_attr->sa_mask & SMB_AT_DOSATTR) { 7465772Sas200622 7475772Sas200622 /* 7485772Sas200622 * "|" in the original xva_mask, which contains 7495772Sas200622 * AT_XVATTR 7505772Sas200622 */ 7515772Sas200622 7525772Sas200622 xvattr->xva_vattr.va_mask |= xva_mask; 7535772Sas200622 7545772Sas200622 XVA_SET_REQ(xvattr, XAT_ARCHIVE); 7555772Sas200622 XVA_SET_REQ(xvattr, XAT_SYSTEM); 7565772Sas200622 XVA_SET_REQ(xvattr, XAT_READONLY); 7575772Sas200622 XVA_SET_REQ(xvattr, XAT_HIDDEN); 7585772Sas200622 7595772Sas200622 /* 7605772Sas200622 * smb_attr->sa_dosattr: If a given bit is not set, 7615772Sas200622 * that indicates that the corresponding field needs 7625772Sas200622 * to be updated with a "0" value. This is done 7635772Sas200622 * implicitly as the xoap->xoa_* fields were bzero'd. 7645772Sas200622 */ 7655772Sas200622 7665772Sas200622 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_ARCHIVE) 7675772Sas200622 xoap->xoa_archive = 1; 7685772Sas200622 7695772Sas200622 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_SYSTEM) 7705772Sas200622 xoap->xoa_system = 1; 7715772Sas200622 7725772Sas200622 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_READONLY) 7735772Sas200622 xoap->xoa_readonly = 1; 7745772Sas200622 7755772Sas200622 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_HIDDEN) 7765772Sas200622 xoap->xoa_hidden = 1; 7775772Sas200622 } 7785772Sas200622 7795772Sas200622 if (smb_attr->sa_mask & SMB_AT_CRTIME) { 7805772Sas200622 /* 7815772Sas200622 * "|" in the original xva_mask, which contains 7825772Sas200622 * AT_XVATTR 7835772Sas200622 */ 7845772Sas200622 7855772Sas200622 xvattr->xva_vattr.va_mask |= xva_mask; 7865772Sas200622 XVA_SET_REQ(xvattr, XAT_CREATETIME); 7875772Sas200622 xoap->xoa_createtime = smb_attr->sa_crtime; 7885772Sas200622 } 7895331Samw } 7905331Samw 7915772Sas200622 7925331Samw /* 7935331Samw * smb_vop_readdir() 7945331Samw * 7955331Samw * Upon return, the "name" field will contain either the on-disk name or, if 7965331Samw * it needs mangling or has a case-insensitive collision, the mangled 7975331Samw * "shortname." 7985331Samw * 7995331Samw * vpp is an optional parameter. If non-NULL, it will contain a pointer to 8005331Samw * the vnode for the name that is looked up (the vnode will be returned held). 8015331Samw * 8025331Samw * od_name is an optional parameter (NULL can be passed if the on-disk name 8035331Samw * is not needed by the caller). 8045331Samw */ 8055331Samw 8065331Samw int 8075331Samw smb_vop_readdir(vnode_t *dvp, uint32_t *cookiep, char *name, int *namelen, 8085772Sas200622 ino64_t *inop, vnode_t **vpp, char *od_name, int flags, cred_t *cr) 8095331Samw { 8105331Samw int num_bytes; 8115331Samw int error = 0; 8125331Samw char *dirbuf = NULL; 8135331Samw 8145331Samw ASSERT(dvp); 8155331Samw ASSERT(cookiep); 8165331Samw ASSERT(name); 8175331Samw ASSERT(namelen); 8185331Samw ASSERT(inop); 8195331Samw ASSERT(cr); 8205331Samw 8215331Samw if (dvp->v_type != VDIR) { 8225331Samw *namelen = 0; 8235331Samw return (ENOTDIR); 8245331Samw } 8255331Samw 8265331Samw if (vpp) 8275331Samw *vpp = NULL; 8285331Samw 8295331Samw dirbuf = kmem_zalloc(SMB_MINLEN_RDDIR_BUF, KM_SLEEP); 8305331Samw num_bytes = SMB_MINLEN_RDDIR_BUF; 8315331Samw 8325331Samw /* 8335331Samw * The goal is to retrieve the first valid entry from *cookiep 8345331Samw * forward. smb_vop_readdir_readpage() collects an 8355331Samw * SMB_MINLEN_RDDIR_BUF-size "page" of directory entry information. 8365331Samw * smb_vop_readdir_entry() attempts to find the first valid entry 8375331Samw * in that page. 8385331Samw */ 8395331Samw 8405331Samw while ((error = smb_vop_readdir_readpage(dvp, dirbuf, *cookiep, 841*7052Samw &num_bytes, cr)) == 0) { 8425331Samw 8435331Samw if (num_bytes <= 0) 8445331Samw break; 8455331Samw 8465331Samw name[0] = '\0'; 8475331Samw 8485331Samw error = smb_vop_readdir_entry(dvp, cookiep, name, namelen, 8496139Sjb150015 inop, vpp, od_name, flags, cr, dirbuf, num_bytes); 8505331Samw 8515331Samw if (error) 8525331Samw break; 8535331Samw 8545331Samw if (*name) 8555331Samw break; 8565331Samw 8575331Samw bzero(dirbuf, SMB_MINLEN_RDDIR_BUF); 8585331Samw num_bytes = SMB_MINLEN_RDDIR_BUF; 8595331Samw } 8605331Samw 8615331Samw 8625331Samw if (error) { 8635331Samw kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 8645331Samw *namelen = 0; 8655331Samw return (error); 8665331Samw } 8675331Samw 8685331Samw if (num_bytes == 0) { /* EOF */ 8695331Samw kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 8705331Samw *cookiep = SMB_EOF; 8715331Samw *namelen = 0; 8725331Samw return (0); 8735331Samw } 8745331Samw 8755331Samw kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 8765331Samw return (0); 8775331Samw } 8785331Samw 8795331Samw /* 8805331Samw * smb_vop_readdir_readpage() 8815331Samw * 8825331Samw * Collects an SMB_MINLEN_RDDIR_BUF "page" of directory entries. (The 8835331Samw * directory entries are returned in an fs-independent format by the 8845331Samw * underlying file system. That is, the "page" of information returned is 8855331Samw * not literally stored on-disk in the format returned.) 8865331Samw * 8875331Samw * Much of the following is borrowed from getdents64() 8885331Samw * 8895331Samw * MAXGETDENTS_SIZE is defined in getdents.c 8905331Samw */ 8915331Samw 8925331Samw #define MAXGETDENTS_SIZE (64 * 1024) 8935331Samw 8945331Samw static int 8955331Samw smb_vop_readdir_readpage(vnode_t *vp, void *buf, uint32_t offset, int *count, 896*7052Samw cred_t *cr) 8975331Samw { 8985331Samw int error = 0; 8995331Samw int rdirent_flags = 0; 9005331Samw int sink; 9015331Samw struct uio auio; 9025331Samw struct iovec aiov; 9035331Samw 9045331Samw if (vp->v_type != VDIR) 9055331Samw return (ENOTDIR); 9065331Samw 907*7052Samw if (vfs_has_feature(vp->v_vfsp, VFSFT_DIRENTFLAGS)) { 9085331Samw /* 9095331Samw * Setting V_RDDIR_ENTFLAGS will cause the buffer to 9105331Samw * be filled with edirent_t structures (instead of 9115331Samw * dirent64_t structures). 9125331Samw */ 9135331Samw rdirent_flags = V_RDDIR_ENTFLAGS; 9145331Samw 9155331Samw if (*count < sizeof (edirent_t)) 9165331Samw return (EINVAL); 9175331Samw } else { 9185331Samw if (*count < sizeof (dirent64_t)) 9195331Samw return (EINVAL); 9205331Samw } 9215331Samw 9225331Samw if (*count > MAXGETDENTS_SIZE) 9235331Samw *count = MAXGETDENTS_SIZE; 9245331Samw 9255331Samw aiov.iov_base = buf; 9265331Samw aiov.iov_len = *count; 9275331Samw auio.uio_iov = &aiov; 9285331Samw auio.uio_iovcnt = 1; 9295331Samw auio.uio_loffset = (uint64_t)offset; 9305331Samw auio.uio_segflg = UIO_SYSSPACE; 9315331Samw auio.uio_resid = *count; 9325331Samw auio.uio_fmode = 0; 9335331Samw 9346600Sas200622 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &smb_ct); 9355772Sas200622 error = VOP_READDIR(vp, &auio, cr, &sink, &smb_ct, rdirent_flags); 9366600Sas200622 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &smb_ct); 9375331Samw 9385331Samw if (error) { 9395331Samw if (error == ENOENT) { 9405331Samw /* Fake EOF if offset is bad due to dropping of lock */ 9415331Samw *count = 0; 9425331Samw return (0); 9435331Samw } else { 9445331Samw return (error); 9455331Samw } 9465331Samw } 9475331Samw 9485331Samw /* 9495331Samw * Windows cannot handle an offset > SMB_EOF. 9505331Samw * Pretend we are at EOF. 9515331Samw */ 9525331Samw 9535331Samw if (auio.uio_loffset > SMB_EOF) { 9545331Samw *count = 0; 9555331Samw return (0); 9565331Samw } 9575331Samw 9585331Samw *count = *count - auio.uio_resid; 9595331Samw return (0); 9605331Samw } 9615331Samw 9625331Samw /* 9635331Samw * smb_vop_readdir_entry() 9645331Samw * 9655331Samw * This function retrieves the first valid entry from the 9665331Samw * SMB_MINLEN_RDDIR_BUF-sized buffer returned by smb_vop_readdir_readpage() 9675331Samw * to smb_vop_readdir(). 9685331Samw * 9695331Samw * Both dirent64_t and edirent_t structures need to be handled. The former is 9705331Samw * needed for file systems that do not support VFSFT_DIRENTFLAGS. The latter 9715331Samw * is required for proper handling of case collisions on file systems that 9725331Samw * support case-insensitivity. edirent_t structures are also used for 9735331Samw * case-sensitive file systems if VFSFT_DIRENTFLAGS is supported. 9745331Samw */ 9755331Samw 9765331Samw static int 9776139Sjb150015 smb_vop_readdir_entry( 9786139Sjb150015 vnode_t *dvp, 9796139Sjb150015 uint32_t *cookiep, 9806139Sjb150015 char *name, 9816139Sjb150015 int *namelen, 9826139Sjb150015 ino64_t *inop, 9836139Sjb150015 vnode_t **vpp, 9846139Sjb150015 char *od_name, 9856139Sjb150015 int flags, 9866139Sjb150015 cred_t *cr, 9876139Sjb150015 char *dirbuf, 9886139Sjb150015 int num_bytes) 9895331Samw { 9905331Samw uint32_t next_cookie; 9915331Samw int ebufsize; 9925331Samw int error = 0; 9935331Samw int len; 9945331Samw int rc; 9955331Samw char shortname[MANGLE_NAMELEN]; 9965331Samw char name83[MANGLE_NAMELEN]; 9975331Samw char *ebuf = NULL; 9985331Samw edirent_t *edp; 9995331Samw dirent64_t *dp = NULL; 10005331Samw vnode_t *vp = NULL; 10015331Samw 10025331Samw ASSERT(dirbuf); 10035331Samw 10045331Samw /* 10055331Samw * Use edirent_t structure for both 10065331Samw */ 1007*7052Samw if (vfs_has_feature(dvp->v_vfsp, VFSFT_DIRENTFLAGS)) { 10085331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 10095331Samw edp = (edirent_t *)dirbuf; 10105331Samw } else { 10115331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 10125331Samw dp = (dirent64_t *)dirbuf; 10135331Samw ebufsize = EDIRENT_RECLEN(MAXNAMELEN); 10145331Samw ebuf = kmem_zalloc(ebufsize, KM_SLEEP); 10155331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 10165331Samw edp = (edirent_t *)ebuf; 10175331Samw } 10185331Samw 10195331Samw while (edp) { 10205331Samw if (dp) 10215331Samw DP_TO_EDP(dp, edp); 10225331Samw 10235331Samw next_cookie = (uint32_t)edp->ed_off; 10245331Samw if (edp->ed_ino == 0) { 10255331Samw *cookiep = next_cookie; 10265331Samw 10275331Samw if (dp) { 10285331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 10295331Samw DP_ADVANCE(dp, dirbuf, num_bytes); 10305331Samw if (dp == NULL) 10315331Samw edp = NULL; 10325331Samw } else { 10335331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 10345331Samw EDP_ADVANCE(edp, dirbuf, num_bytes); 10355331Samw } 10365331Samw continue; 10375331Samw } 10385331Samw 10395331Samw len = strlen(edp->ed_name); 10405331Samw 10415331Samw if (*namelen < len) { 10425331Samw *namelen = 0; 10435331Samw 10445331Samw if (ebuf) 10455331Samw kmem_free(ebuf, ebufsize); 10465331Samw 10475331Samw return (EOVERFLOW); 10485331Samw } 10495331Samw 10505331Samw /* 10515331Samw * Do not pass SMB_IGNORE_CASE to smb_vop_lookup 10525331Samw */ 10535331Samw 10545331Samw error = smb_vop_lookup(dvp, edp->ed_name, vpp ? vpp : &vp, 10555772Sas200622 od_name, 0, NULL, cr); 10565331Samw 10575331Samw if (error) { 10585331Samw if (error == ENOENT) { 10595331Samw *cookiep = (uint32_t)next_cookie; 10605331Samw 10615331Samw if (dp) { 10625331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 10635331Samw DP_ADVANCE(dp, dirbuf, num_bytes); 10645331Samw if (dp == NULL) 10655331Samw edp = NULL; 10665331Samw } else { 10675331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 10685331Samw EDP_ADVANCE(edp, dirbuf, num_bytes); 10695331Samw } 10705331Samw continue; 10715331Samw } 10725331Samw 10735331Samw 10745331Samw *namelen = 0; 10755331Samw 10765331Samw if (ebuf) 10775331Samw kmem_free(ebuf, ebufsize); 10785331Samw 10795331Samw return (error); 10805331Samw } 10815331Samw 10825331Samw if ((flags & SMB_IGNORE_CASE) && ED_CASE_CONFLICTS(edp)) { 10835331Samw rc = smb_mangle_name(edp->ed_ino, edp->ed_name, 10845331Samw shortname, name83, 1); 10855331Samw 10865331Samw if (rc == 1) { /* success */ 10875331Samw (void) strlcpy(name, shortname, *namelen + 1); 10885331Samw *namelen = strlen(shortname); 10895331Samw } else { 10905331Samw (void) strlcpy(name, edp->ed_name, 10915331Samw *namelen + 1); 10925331Samw name[*namelen] = '\0'; 10935331Samw } 10945331Samw 10955331Samw } else { 10965331Samw (void) strlcpy(name, edp->ed_name, *namelen + 1); 10975331Samw *namelen = len; 10985331Samw } 10995331Samw 11005331Samw if (vpp == NULL) 11015331Samw VN_RELE(vp); 11025331Samw 11035331Samw if (inop) 11045331Samw *inop = edp->ed_ino; 11055331Samw 11065331Samw *cookiep = (uint32_t)next_cookie; 11075331Samw break; 11085331Samw } 11095331Samw 11105331Samw if (ebuf) 11115331Samw kmem_free(ebuf, ebufsize); 11125331Samw 11135331Samw return (error); 11145331Samw } 11155331Samw 11165331Samw /* 11175331Samw * smb_sa_to_va_mask 11185331Samw * 11195331Samw * Set va_mask by running through the SMB_AT_* #define's and 11205331Samw * setting those bits that correspond to the SMB_AT_* bits 11215331Samw * set in sa_mask. 11225331Samw */ 11235331Samw 11245331Samw void 11255331Samw smb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp) 11265331Samw { 11275331Samw int i; 11285331Samw uint_t smask; 11295331Samw 11305331Samw smask = (sa_mask); 11315331Samw for (i = SMB_AT_TYPE; (i < SMB_AT_MAX) && (smask != 0); ++i) { 11325331Samw if (smask & 1) 11335331Samw *(va_maskp) |= smb_attrmap[i]; 11345331Samw 11355331Samw smask >>= 1; 11365331Samw } 11375331Samw } 11385331Samw 11395331Samw /* 11405331Samw * smb_vop_getdents() 11415331Samw * 11425331Samw * Upon success, the smb_node corresponding to each entry returned will 11435331Samw * have a reference taken on it. These will be released in 11445331Samw * smb_trans2_find_get_dents(). 11455331Samw * 11465331Samw * If an error is returned from this routine, a list of already processed 11475331Samw * entries will be returned. The smb_nodes corresponding to these entries 11485331Samw * will be referenced, and will be released in smb_trans2_find_get_dents(). 11495331Samw * 11505331Samw * The returned dp->d_name field will contain either the on-disk name or, if 11515331Samw * it needs mangling or has a case-insensitive collision, the mangled 11525331Samw * "shortname." In this case, the on-disk name can be retrieved from the 11535331Samw * smb_node's od_name (the smb_node is passed to smb_gather_dents_info()). 11545331Samw */ 11555331Samw 11565331Samw int /*ARGSUSED*/ 11575331Samw smb_vop_getdents( 11585331Samw smb_node_t *dir_snode, 11595331Samw uint32_t *cookiep, 11605331Samw uint64_t *verifierp, 11615331Samw int32_t *dircountp, 11625331Samw char *arg, 11635331Samw char *pattern, 11645331Samw uint32_t flags, 11655331Samw smb_request_t *sr, 11665772Sas200622 cred_t *cr) 11675331Samw { 11685331Samw int error = 0; 11695331Samw int maxentries; 11705331Samw int num_bytes; 11715331Samw int resid; 11725331Samw char *dirbuf = NULL; 11735331Samw vnode_t *dvp; 11745331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 11755331Samw smb_dent_info_hdr_t *ihdr = (smb_dent_info_hdr_t *)arg; 11765331Samw 11775331Samw dvp = dir_snode->vp; 11785331Samw 11795331Samw resid = ihdr->uio.uio_resid; 11805331Samw maxentries = resid / SMB_MAX_DENT_INFO_SIZE; 11815331Samw 11825331Samw bzero(ihdr->iov->iov_base, resid); 11835331Samw 11845331Samw dirbuf = kmem_alloc(SMB_MINLEN_RDDIR_BUF, KM_SLEEP); 11855331Samw 11865331Samw while (maxentries) { 11875331Samw 11885331Samw bzero(dirbuf, SMB_MINLEN_RDDIR_BUF); 11895331Samw 11905331Samw num_bytes = SMB_MINLEN_RDDIR_BUF; 11915331Samw error = smb_vop_readdir_readpage(dvp, dirbuf, *cookiep, 1192*7052Samw &num_bytes, cr); 11935331Samw 11945331Samw if (error || (num_bytes <= 0)) 11955331Samw break; 11965331Samw 11975331Samw error = smb_vop_getdents_entries(dir_snode, cookiep, dircountp, 11985772Sas200622 arg, flags, sr, cr, dirbuf, &maxentries, num_bytes, 11995331Samw pattern); 12005331Samw 12015331Samw if (error) 12025331Samw goto out; 12035331Samw } 12045331Samw 12055331Samw if (num_bytes < 0) { 12065331Samw error = -1; 12075331Samw } else if (num_bytes == 0) { 12085331Samw *cookiep = SMB_EOF; 12095331Samw error = 0; 12105331Samw } else { 12115331Samw error = 0; 12125331Samw } 12135331Samw 12145331Samw out: 12155331Samw if (dirbuf) 12165331Samw kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 12175331Samw 12185331Samw return (error); 12195331Samw } 12205331Samw 12215331Samw /* 12225331Samw * smb_vop_getdents_entries() 12235331Samw * 12245331Samw * This function retrieves names from the SMB_MINLEN_RDDIR_BUF-sized buffer 12255331Samw * returned by smb_vop_readdir_readpage() to smb_vop_getdents(). 12265331Samw * 12275331Samw * Both dirent64_t and edirent_t structures need to be handled. The former is 12285331Samw * needed for file systems that do not support VFSFT_DIRENTFLAGS. The latter 12295331Samw * is required for properly handling case collisions on file systems that 12305331Samw * support case-insensitivity. edirent_t is also used on case-sensitive 12315331Samw * file systems where VFSFT_DIRENTFLAGS is available. 12325331Samw */ 12335331Samw 12345331Samw static int 12355331Samw smb_vop_getdents_entries( 12365331Samw smb_node_t *dir_snode, 12375331Samw uint32_t *cookiep, 12385331Samw int32_t *dircountp, 12395331Samw char *arg, 12405331Samw uint32_t flags, 12416139Sjb150015 smb_request_t *sr, 12425331Samw cred_t *cr, 12435331Samw char *dirbuf, 12445331Samw int *maxentries, 12455331Samw int num_bytes, 12465331Samw char *pattern) 12475331Samw { 12485331Samw uint32_t next_cookie; 12495331Samw int ebufsize; 12505331Samw char *tmp_name; 12515331Samw int error; 12525331Samw int rc; 12535331Samw char shortname[MANGLE_NAMELEN]; 12545331Samw char name83[MANGLE_NAMELEN]; 12555331Samw char *ebuf = NULL; 12565331Samw dirent64_t *dp = NULL; 12575331Samw edirent_t *edp; 12585331Samw smb_node_t *ret_snode; 12595331Samw smb_attr_t ret_attr; 12605331Samw vnode_t *dvp; 12615331Samw vnode_t *fvp; 12625331Samw 12635331Samw ASSERT(dirbuf); 12645331Samw 12655331Samw dvp = dir_snode->vp; 12665331Samw 12675331Samw if (vfs_has_feature(dvp->v_vfsp, VFSFT_DIRENTFLAGS)) { 12685331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 12695331Samw edp = (edirent_t *)dirbuf; 12705331Samw } else { 12715331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 12725331Samw dp = (dirent64_t *)dirbuf; 12735331Samw ebufsize = EDIRENT_RECLEN(MAXNAMELEN); 12745331Samw ebuf = kmem_zalloc(ebufsize, KM_SLEEP); 12755331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 12765331Samw edp = (edirent_t *)ebuf; 12775331Samw } 12785331Samw 12795331Samw while (edp) { 12805331Samw if (dp) 12815331Samw DP_TO_EDP(dp, edp); 12825331Samw 12835331Samw if (*maxentries == 0) 12845331Samw break; 12855331Samw 12865331Samw next_cookie = (uint32_t)edp->ed_off; 12875331Samw 12885331Samw if (edp->ed_ino == 0) { 12895331Samw *cookiep = next_cookie; 12905331Samw if (dp) { 12915331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 12925331Samw DP_ADVANCE(dp, dirbuf, num_bytes); 12935331Samw if (dp == NULL) 12945331Samw edp = NULL; 12955331Samw } else { 12965331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 12975331Samw EDP_ADVANCE(edp, dirbuf, num_bytes); 12985331Samw } 12995331Samw continue; 13005331Samw } 13015331Samw 13025331Samw error = smb_vop_lookup(dvp, edp->ed_name, &fvp, 13035772Sas200622 NULL, 0, NULL, cr); 13045331Samw 13055331Samw if (error) { 13065331Samw if (error == ENOENT) { 13075331Samw *cookiep = next_cookie; 13085331Samw if (dp) { 13095331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 13105331Samw DP_ADVANCE(dp, dirbuf, 13115331Samw num_bytes); 13125331Samw if (dp == NULL) 13135331Samw edp = NULL; 13145331Samw } else { 13155331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 13165331Samw EDP_ADVANCE(edp, dirbuf, 13175331Samw num_bytes); 13185331Samw } 13195331Samw continue; 13205331Samw } 13215331Samw if (ebuf) 13225331Samw kmem_free(ebuf, ebufsize); 13235331Samw 13245331Samw return (error); 13255331Samw } 13265331Samw 13275331Samw ret_snode = smb_node_lookup(sr, NULL, cr, fvp, 13285331Samw edp->ed_name, dir_snode, NULL, &ret_attr); 13295331Samw 13305331Samw if (ret_snode == NULL) { 13315331Samw VN_RELE(fvp); 13325331Samw 13335331Samw if (ebuf) 13345331Samw kmem_free(ebuf, ebufsize); 13355331Samw 13365331Samw return (ENOMEM); 13375331Samw } 13385331Samw 13395331Samw if (smb_match_name(edp->ed_ino, edp->ed_name, shortname, 13405331Samw name83, pattern, (flags & SMB_IGNORE_CASE))) { 13415331Samw 13425331Samw tmp_name = edp->ed_name; 13435331Samw 13445331Samw if ((flags & SMB_IGNORE_CASE) && 13455331Samw ED_CASE_CONFLICTS(edp)) { 13465331Samw rc = smb_mangle_name(edp->ed_ino, edp->ed_name, 13475331Samw shortname, name83, 1); 13485331Samw if (rc == 1) 13495331Samw tmp_name = shortname; 13505331Samw } else { 13515331Samw rc = smb_mangle_name(edp->ed_ino, edp->ed_name, 13525331Samw shortname, name83, 0); 13535331Samw } 13545331Samw 13555331Samw if (rc != 1) { 13565331Samw (void) strlcpy(shortname, edp->ed_name, 13575331Samw MANGLE_NAMELEN); 13585331Samw (void) strlcpy(name83, edp->ed_name, 13595331Samw MANGLE_NAMELEN); 13605331Samw shortname[MANGLE_NAMELEN - 1] = '\0'; 13615331Samw name83[MANGLE_NAMELEN - 1] = '\0'; 13625331Samw } 13635331Samw 13645331Samw error = smb_gather_dents_info(arg, edp->ed_ino, 13655331Samw strlen(tmp_name), tmp_name, next_cookie, dircountp, 13665331Samw &ret_attr, ret_snode, shortname, name83); 13675331Samw 13685331Samw if (error > 0) { 13695331Samw if (ebuf) 13705331Samw kmem_free(ebuf, ebufsize); 13715331Samw return (error); 13725331Samw } 13735331Samw 13745331Samw /* 13755331Samw * Treat errors from smb_gather_dents_info() that are 13765331Samw * < 0 the same as EOF. 13775331Samw */ 13785331Samw if (error < 0) { 13795331Samw if (ebuf) 13805331Samw kmem_free(ebuf, ebufsize); 13815331Samw *maxentries = 0; 13825331Samw return (0); 13835331Samw } 13845331Samw (*maxentries)--; 13855331Samw } else { 13865331Samw smb_node_release(ret_snode); 13875331Samw } 13885331Samw 13895331Samw *cookiep = next_cookie; 13905331Samw 13915331Samw if (dp) { 13925331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 13935331Samw DP_ADVANCE(dp, dirbuf, num_bytes); 13945331Samw if (dp == NULL) 13955331Samw edp = NULL; 13965331Samw } else { 13975331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 13985331Samw EDP_ADVANCE(edp, dirbuf, num_bytes); 13995331Samw } 14005331Samw } 14015331Samw 14025331Samw if (ebuf) 14035331Samw kmem_free(ebuf, ebufsize); 14045331Samw 14055331Samw return (0); 14065331Samw } 14075331Samw 14085331Samw /* 14095331Samw * smb_vop_stream_lookup() 14105331Samw * 14115331Samw * The name returned in od_name is the on-disk name of the stream with the 14125331Samw * SMB_STREAM_PREFIX stripped off. od_name should be allocated to MAXNAMELEN 14135331Samw * by the caller. 14145331Samw */ 14155331Samw 14165331Samw int 14176139Sjb150015 smb_vop_stream_lookup( 14186139Sjb150015 vnode_t *fvp, 14196139Sjb150015 char *stream_name, 14206139Sjb150015 vnode_t **vpp, 14216139Sjb150015 char *od_name, 14226139Sjb150015 vnode_t **xattrdirvpp, 14236139Sjb150015 int flags, 14246139Sjb150015 vnode_t *rootvp, 14256139Sjb150015 cred_t *cr) 14265331Samw { 14275331Samw char *solaris_stream_name; 14285331Samw char *name; 14295331Samw int error; 14305331Samw 14315331Samw if ((error = smb_vop_lookup_xattrdir(fvp, xattrdirvpp, 14325772Sas200622 LOOKUP_XATTR | CREATE_XATTR_DIR, cr)) != 0) 14335331Samw return (error); 14345331Samw 14355331Samw /* 14365331Samw * Prepend SMB_STREAM_PREFIX to stream name 14375331Samw */ 14385331Samw 14395331Samw solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 14405331Samw (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX, 14415331Samw stream_name); 14425331Samw 14435331Samw /* 14445331Samw * "name" will hold the on-disk name returned from smb_vop_lookup 14455331Samw * for the stream, including the SMB_STREAM_PREFIX. 14465331Samw */ 14475331Samw 14485331Samw name = kmem_zalloc(MAXNAMELEN, KM_SLEEP); 14495331Samw 14505331Samw if ((error = smb_vop_lookup(*xattrdirvpp, solaris_stream_name, vpp, 14515772Sas200622 name, flags, rootvp, cr)) != 0) { 14525331Samw VN_RELE(*xattrdirvpp); 14535331Samw } else { 14545331Samw (void) strlcpy(od_name, &(name[SMB_STREAM_PREFIX_LEN]), 14555331Samw MAXNAMELEN); 14565331Samw } 14575331Samw 14585331Samw kmem_free(solaris_stream_name, MAXNAMELEN); 14595331Samw kmem_free(name, MAXNAMELEN); 14605331Samw 14615331Samw return (error); 14625331Samw } 14635331Samw 14645331Samw int 14655331Samw smb_vop_stream_create(vnode_t *fvp, char *stream_name, smb_attr_t *attr, 14665772Sas200622 vnode_t **vpp, vnode_t **xattrdirvpp, int flags, cred_t *cr) 14675331Samw { 14685331Samw char *solaris_stream_name; 14695331Samw int error; 14705331Samw 14715331Samw if ((error = smb_vop_lookup_xattrdir(fvp, xattrdirvpp, 14725772Sas200622 LOOKUP_XATTR | CREATE_XATTR_DIR, cr)) != 0) 14735331Samw return (error); 14745331Samw 14755331Samw /* 14765331Samw * Prepend SMB_STREAM_PREFIX to stream name 14775331Samw */ 14785331Samw 14795331Samw solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 14805331Samw (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX, 14815331Samw stream_name); 14825331Samw 14835331Samw if ((error = smb_vop_create(*xattrdirvpp, solaris_stream_name, attr, 14845772Sas200622 vpp, flags, cr, NULL)) != 0) 14855331Samw VN_RELE(*xattrdirvpp); 14865331Samw 14875331Samw kmem_free(solaris_stream_name, MAXNAMELEN); 14885331Samw 14895331Samw return (error); 14905331Samw } 14915331Samw 14925331Samw int 14935772Sas200622 smb_vop_stream_remove(vnode_t *vp, char *stream_name, int flags, cred_t *cr) 14945331Samw { 14955331Samw char *solaris_stream_name; 14965331Samw vnode_t *xattrdirvp; 14975331Samw int error; 14985331Samw 14996139Sjb150015 error = smb_vop_lookup_xattrdir(vp, &xattrdirvp, LOOKUP_XATTR, cr); 15006139Sjb150015 if (error != 0) 15015331Samw return (error); 15025331Samw 15035331Samw /* 15045331Samw * Prepend SMB_STREAM_PREFIX to stream name 15055331Samw */ 15065331Samw 15075331Samw solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 15085331Samw (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX, 15095331Samw stream_name); 15105331Samw 15115331Samw /* XXX might have to use kcred */ 15125772Sas200622 error = smb_vop_remove(xattrdirvp, solaris_stream_name, flags, cr); 15135331Samw 15145331Samw kmem_free(solaris_stream_name, MAXNAMELEN); 15155331Samw 15165331Samw return (error); 15175331Samw } 15185331Samw 15195331Samw /* 15205331Samw * smb_vop_stream_readdir() 15215331Samw * 15225331Samw * Note: stream_info.size is not filled in in this routine. 15235331Samw * It needs to be filled in by the caller due to the parameters for getattr. 15245331Samw * 15255331Samw * stream_info.name is set to the on-disk stream name with the SMB_STREAM_PREFIX 15265331Samw * removed. 15275331Samw */ 15285331Samw 15295331Samw int 15305331Samw smb_vop_stream_readdir(vnode_t *fvp, uint32_t *cookiep, 15315331Samw struct fs_stream_info *stream_info, vnode_t **vpp, vnode_t **xattrdirvpp, 15325772Sas200622 int flags, cred_t *cr) 15335331Samw { 15346849Sjb150015 int nsize; 15355331Samw int error = 0; 15365331Samw ino64_t ino; 15375331Samw char *tmp_name; 15385331Samw vnode_t *xattrdirvp; 15395331Samw vnode_t *vp; 15405331Samw 15415331Samw if ((error = smb_vop_lookup_xattrdir(fvp, &xattrdirvp, LOOKUP_XATTR, 15425772Sas200622 cr)) != 0) 15435331Samw return (error); 15445331Samw 15455331Samw bzero(stream_info->name, sizeof (stream_info->name)); 15465331Samw stream_info->size = 0; 15475331Samw 15485331Samw tmp_name = kmem_zalloc(MAXNAMELEN, KM_SLEEP); 15495331Samw 15505331Samw for (;;) { 15516849Sjb150015 nsize = MAXNAMELEN-1; 15525331Samw error = smb_vop_readdir(xattrdirvp, cookiep, tmp_name, &nsize, 1553*7052Samw &ino, &vp, NULL, flags, cr); 15545331Samw 15555331Samw if (error || (*cookiep == SMB_EOF)) 15565331Samw break; 15575331Samw 15585331Samw if (strncmp(tmp_name, SMB_STREAM_PREFIX, 15595331Samw SMB_STREAM_PREFIX_LEN)) { 15605331Samw VN_RELE(vp); 15615331Samw continue; 15625331Samw } 15635331Samw 15645331Samw tmp_name[nsize] = '\0'; 15655331Samw (void) strlcpy(stream_info->name, 15665331Samw &(tmp_name[SMB_STREAM_PREFIX_LEN]), 15675331Samw sizeof (stream_info->name)); 15685331Samw 15695331Samw nsize -= SMB_STREAM_PREFIX_LEN; 15705331Samw break; 15715331Samw } 15725331Samw 15735331Samw if ((error == 0) && nsize) { 15745331Samw if (vpp) 15755331Samw *vpp = vp; 15765331Samw else 15775331Samw VN_RELE(vp); 15785331Samw 15795331Samw if (xattrdirvpp) 15805331Samw *xattrdirvpp = xattrdirvp; 15815331Samw else 15825331Samw VN_RELE(xattrdirvp); 15835331Samw 15845781Sjc198820 } else { 15855781Sjc198820 VN_RELE(xattrdirvp); 15865331Samw } 15875331Samw 15885331Samw kmem_free(tmp_name, MAXNAMELEN); 15895331Samw 15905331Samw return (error); 15915331Samw } 15925331Samw 15935331Samw int 15945331Samw smb_vop_lookup_xattrdir(vnode_t *fvp, vnode_t **xattrdirvpp, int flags, 15955772Sas200622 cred_t *cr) 15965331Samw { 15975331Samw int error; 15985331Samw 15995772Sas200622 error = VOP_LOOKUP(fvp, "", xattrdirvpp, NULL, flags, NULL, cr, 16005772Sas200622 &smb_ct, NULL, NULL); 16015331Samw return (error); 16025331Samw } 16035331Samw 16045331Samw /* 16055331Samw * smb_vop_traverse_check() 16065331Samw * 16075331Samw * This function checks to see if the passed-in vnode has a file system 16085331Samw * mounted on it. If it does, the mount point is "traversed" and the 16095331Samw * vnode for the root of the file system is returned. 16105331Samw */ 16115331Samw 16125331Samw int 16135331Samw smb_vop_traverse_check(vnode_t **vpp) 16145331Samw { 16155331Samw int error; 16165331Samw 16175331Samw if (vn_mountedvfs(*vpp) == 0) 16185331Samw return (0); 16195331Samw 16205331Samw /* 16215331Samw * traverse() may return a different held vnode, even in the error case. 16225331Samw * If it returns a different vnode, it will have released the original. 16235331Samw */ 16245331Samw 16255331Samw error = traverse(vpp); 16265331Samw 16275331Samw return (error); 16285331Samw } 16295331Samw 16305331Samw int /*ARGSUSED*/ 16315331Samw smb_vop_statfs(vnode_t *vp, struct statvfs64 *statp, cred_t *cr) 16325331Samw { 16335331Samw int error; 16345331Samw 16355331Samw error = VFS_STATVFS(vp->v_vfsp, statp); 16365331Samw 16375331Samw return (error); 16385331Samw } 16395331Samw 16405331Samw /* 16415331Samw * smb_vop_acl_read 16425331Samw * 16435331Samw * Reads the ACL of the specified file into 'aclp'. 16445331Samw * acl_type is the type of ACL which the filesystem supports. 16455331Samw * 16465331Samw * Caller has to free the allocated memory for aclp by calling 16475331Samw * acl_free(). 16485331Samw */ 16495331Samw int 16505331Samw smb_vop_acl_read(vnode_t *vp, acl_t **aclp, int flags, acl_type_t acl_type, 16515772Sas200622 cred_t *cr) 16525331Samw { 16535331Samw int error; 16545331Samw vsecattr_t vsecattr; 16555331Samw 16565331Samw ASSERT(vp); 16575331Samw ASSERT(aclp); 16585331Samw 16595331Samw *aclp = NULL; 16605331Samw bzero(&vsecattr, sizeof (vsecattr_t)); 16615331Samw 16625331Samw switch (acl_type) { 16635331Samw case ACLENT_T: 16645331Samw vsecattr.vsa_mask = VSA_ACL | VSA_ACLCNT | VSA_DFACL | 16655331Samw VSA_DFACLCNT; 16665331Samw break; 16675331Samw 16685331Samw case ACE_T: 16695331Samw vsecattr.vsa_mask = VSA_ACE | VSA_ACECNT | VSA_ACE_ACLFLAGS; 16705331Samw break; 16715331Samw 16725331Samw default: 16735331Samw return (EINVAL); 16745331Samw } 16755331Samw 16765772Sas200622 if (error = VOP_GETSECATTR(vp, &vsecattr, flags, cr, &smb_ct)) 16775331Samw return (error); 16785331Samw 16795521Sas200622 *aclp = smb_fsacl_from_vsa(&vsecattr, acl_type); 16805331Samw if (vp->v_type == VDIR) 16815331Samw (*aclp)->acl_flags |= ACL_IS_DIR; 16825331Samw 16835331Samw return (0); 16845331Samw } 16855331Samw 16865331Samw /* 16875331Samw * smb_vop_acl_write 16885331Samw * 16895331Samw * Writes the given ACL in aclp for the specified file. 16905331Samw */ 16915331Samw int 16925772Sas200622 smb_vop_acl_write(vnode_t *vp, acl_t *aclp, int flags, cred_t *cr) 16935331Samw { 16945331Samw int error; 16955331Samw vsecattr_t vsecattr; 16965331Samw int aclbsize; 16975331Samw 16985331Samw ASSERT(vp); 16995331Samw ASSERT(aclp); 17005331Samw 17015521Sas200622 error = smb_fsacl_to_vsa(aclp, &vsecattr, &aclbsize); 17025331Samw 17035331Samw if (error == 0) { 17046600Sas200622 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &smb_ct); 17055772Sas200622 error = VOP_SETSECATTR(vp, &vsecattr, flags, cr, &smb_ct); 17066600Sas200622 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &smb_ct); 17075331Samw } 17085331Samw 17095331Samw if (aclbsize && vsecattr.vsa_aclentp) 17105331Samw kmem_free(vsecattr.vsa_aclentp, aclbsize); 17115331Samw 17125331Samw return (error); 17135331Samw } 17145331Samw 17155331Samw /* 17165331Samw * smb_vop_acl_type 17175331Samw * 17185331Samw * Determines the ACL type for the given vnode. 17195331Samw * ACLENT_T is a Posix ACL and ACE_T is a ZFS ACL. 17205331Samw */ 17215331Samw acl_type_t 17225331Samw smb_vop_acl_type(vnode_t *vp) 17235331Samw { 17245331Samw int error; 17255331Samw ulong_t whichacl; 17265331Samw 17275331Samw error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &whichacl, kcred, NULL); 17285331Samw if (error != 0) { 17295331Samw /* 17305331Samw * If we got an error, then the filesystem 17315331Samw * likely does not understand the _PC_ACL_ENABLED 17325331Samw * pathconf. In this case, we fall back to trying 17335331Samw * POSIX-draft (aka UFS-style) ACLs. 17345331Samw */ 17355331Samw whichacl = _ACL_ACLENT_ENABLED; 17365331Samw } 17375331Samw 17385331Samw if (!(whichacl & (_ACL_ACE_ENABLED | _ACL_ACLENT_ENABLED))) { 17395331Samw /* 17405331Samw * If the file system supports neither ACE nor 17415331Samw * ACLENT ACLs we will fall back to UFS-style ACLs 17425331Samw * like we did above if there was an error upon 17435331Samw * calling VOP_PATHCONF. 17445331Samw * 17455331Samw * ACE and ACLENT type ACLs are the only interfaces 17465331Samw * supported thus far. If any other bits are set on 17475331Samw * 'whichacl' upon return from VOP_PATHCONF, we will 17485331Samw * ignore them. 17495331Samw */ 17505331Samw whichacl = _ACL_ACLENT_ENABLED; 17515331Samw } 17525331Samw 17535331Samw if (whichacl == _ACL_ACLENT_ENABLED) 17545331Samw return (ACLENT_T); 17555331Samw 17565331Samw return (ACE_T); 17575331Samw } 17585331Samw 17595331Samw static int zfs_perms[] = { 17605331Samw ACE_READ_DATA, ACE_WRITE_DATA, ACE_APPEND_DATA, ACE_READ_NAMED_ATTRS, 17615331Samw ACE_WRITE_NAMED_ATTRS, ACE_EXECUTE, ACE_DELETE_CHILD, 17625331Samw ACE_READ_ATTRIBUTES, ACE_WRITE_ATTRIBUTES, ACE_DELETE, ACE_READ_ACL, 17635331Samw ACE_WRITE_ACL, ACE_WRITE_OWNER, ACE_SYNCHRONIZE 17645331Samw }; 17655331Samw 17665331Samw static int unix_perms[] = { VREAD, VWRITE, VEXEC }; 17675331Samw /* 17685331Samw * smb_vop_eaccess 17695331Samw * 17705331Samw * Returns the effective permission of the given credential for the 17715331Samw * specified object. 17725331Samw * 17735331Samw * This is just a workaround. We need VFS/FS support for this. 17745331Samw */ 17755331Samw void 17765331Samw smb_vop_eaccess(vnode_t *vp, int *mode, int flags, vnode_t *dir_vp, cred_t *cr) 17775331Samw { 17785331Samw int error, i; 17795331Samw int pnum; 17805331Samw 17815331Samw *mode = 0; 17825331Samw 17835331Samw if (flags == V_ACE_MASK) { 17845331Samw pnum = sizeof (zfs_perms) / sizeof (int); 17855331Samw 17865331Samw for (i = 0; i < pnum; i++) { 17875331Samw error = smb_vop_access(vp, zfs_perms[i], flags, 17885331Samw dir_vp, cr); 17895331Samw if (error == 0) 17905331Samw *mode |= zfs_perms[i]; 17915331Samw } 17925331Samw } else { 17935331Samw pnum = sizeof (unix_perms) / sizeof (int); 17945331Samw 17955331Samw for (i = 0; i < pnum; i++) { 17965331Samw error = smb_vop_access(vp, unix_perms[i], flags, 17975331Samw dir_vp, cr); 17985331Samw if (error == 0) 17995331Samw *mode |= unix_perms[i]; 18005331Samw } 18015331Samw } 18025331Samw } 18035772Sas200622 18045772Sas200622 /* 18055772Sas200622 * smb_vop_shrlock() 18065772Sas200622 * 18075772Sas200622 * See comments for smb_fsop_shrlock() 18085772Sas200622 */ 18095772Sas200622 18105772Sas200622 int 18115772Sas200622 smb_vop_shrlock(vnode_t *vp, uint32_t uniq_fid, uint32_t desired_access, 18125772Sas200622 uint32_t share_access, cred_t *cr) 18135772Sas200622 { 18145772Sas200622 struct shrlock shr; 18155772Sas200622 struct shr_locowner shr_own; 18165772Sas200622 short new_access = 0; 18175772Sas200622 short deny = 0; 18185772Sas200622 int flag = 0; 18195772Sas200622 int cmd; 18205772Sas200622 18215772Sas200622 cmd = (nbl_need_check(vp)) ? F_SHARE_NBMAND : F_SHARE; 18225772Sas200622 18235772Sas200622 /* 18245772Sas200622 * Check if this is a metadata access 18255772Sas200622 */ 18265772Sas200622 18275772Sas200622 if ((desired_access & FILE_DATA_ALL) == 0) { 18285772Sas200622 new_access |= F_MDACC; 18295772Sas200622 } else { 18305772Sas200622 if (desired_access & (ACE_READ_DATA | ACE_EXECUTE)) { 18315772Sas200622 new_access |= F_RDACC; 18325772Sas200622 flag |= FREAD; 18335772Sas200622 } 18345772Sas200622 18355772Sas200622 if (desired_access & (ACE_WRITE_DATA | ACE_APPEND_DATA | 18365772Sas200622 ACE_ADD_FILE)) { 18375772Sas200622 new_access |= F_WRACC; 18385772Sas200622 flag |= FWRITE; 18395772Sas200622 } 18405772Sas200622 18415772Sas200622 if (SMB_DENY_READ(share_access)) { 18425772Sas200622 deny |= F_RDDNY; 18435772Sas200622 } 18445772Sas200622 18455772Sas200622 if (SMB_DENY_WRITE(share_access)) { 18465772Sas200622 deny |= F_WRDNY; 18475772Sas200622 } 18485772Sas200622 18495772Sas200622 if (cmd == F_SHARE_NBMAND) { 18505772Sas200622 if (desired_access & ACE_DELETE) 18515772Sas200622 new_access |= F_RMACC; 18525772Sas200622 18535772Sas200622 if (SMB_DENY_DELETE(share_access)) { 18545772Sas200622 deny |= F_RMDNY; 18555772Sas200622 } 18565772Sas200622 } 18575772Sas200622 } 18585772Sas200622 18595772Sas200622 shr.s_access = new_access; 18605772Sas200622 shr.s_deny = deny; 18615772Sas200622 shr.s_sysid = smb_ct.cc_sysid; 18625772Sas200622 shr.s_pid = uniq_fid; 18635772Sas200622 shr.s_own_len = sizeof (shr_own); 18645772Sas200622 shr.s_owner = (caddr_t)&shr_own; 18655772Sas200622 shr_own.sl_id = shr.s_sysid; 18665772Sas200622 shr_own.sl_pid = shr.s_pid; 18675772Sas200622 18685772Sas200622 return (VOP_SHRLOCK(vp, cmd, &shr, flag, cr, NULL)); 18695772Sas200622 } 18705772Sas200622 18715772Sas200622 int 18725772Sas200622 smb_vop_unshrlock(vnode_t *vp, uint32_t uniq_fid, cred_t *cr) 18735772Sas200622 { 18745772Sas200622 struct shrlock shr; 18755772Sas200622 struct shr_locowner shr_own; 18765772Sas200622 18775772Sas200622 /* 18785772Sas200622 * For s_access and s_deny, we do not need to pass in the original 18795772Sas200622 * values. 18805772Sas200622 */ 18815772Sas200622 18825772Sas200622 shr.s_access = 0; 18835772Sas200622 shr.s_deny = 0; 18845772Sas200622 shr.s_sysid = smb_ct.cc_sysid; 18855772Sas200622 shr.s_pid = uniq_fid; 18865772Sas200622 shr.s_own_len = sizeof (shr_own); 18875772Sas200622 shr.s_owner = (caddr_t)&shr_own; 18885772Sas200622 shr_own.sl_id = shr.s_sysid; 18895772Sas200622 shr_own.sl_pid = shr.s_pid; 18905772Sas200622 18915772Sas200622 return (VOP_SHRLOCK(vp, F_UNSHARE, &shr, 0, cr, NULL)); 18925772Sas200622 } 18936600Sas200622 18946600Sas200622 int 18956600Sas200622 smb_vop_frlock(vnode_t *vp, cred_t *cr, int flag, flock64_t *bf) 18966600Sas200622 { 18976600Sas200622 int cmd = nbl_need_check(vp) ? F_SETLK_NBMAND : F_SETLK; 18986600Sas200622 flk_callback_t flk_cb; 18996600Sas200622 19006600Sas200622 flk_init_callback(&flk_cb, smb_lock_frlock_callback, NULL); 19016600Sas200622 19026600Sas200622 return (VOP_FRLOCK(vp, cmd, bf, flag, 0, &flk_cb, cr, &smb_ct)); 19036600Sas200622 } 19046600Sas200622 19056600Sas200622 static callb_cpr_t * 19066600Sas200622 /* ARGSUSED */ 19076600Sas200622 smb_lock_frlock_callback(flk_cb_when_t when, void *error) 19086600Sas200622 { 19096600Sas200622 return (0); 19106600Sas200622 } 1911