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 546139Sjb150015 smb_vop_readdir_readpage(vnode_t *, void *, uint32_t, int *, cred_t *, int); 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 73*6600Sas200622 static 74*6600Sas200622 callb_cpr_t *smb_lock_frlock_callback(flk_cb_when_t, void *); 75*6600Sas200622 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 167*6600Sas200622 int 168*6600Sas200622 smb_vop_other_opens(vnode_t *vp, int mode) 169*6600Sas200622 { 170*6600Sas200622 return (((mode & FWRITE) && vn_has_other_opens(vp, V_WRITE)) || 171*6600Sas200622 (((mode & FWRITE) == 0) && vn_is_opened(vp, V_WRITE)) || 172*6600Sas200622 ((mode & FREAD) && vn_has_other_opens(vp, V_READ)) || 173*6600Sas200622 (((mode & FREAD) == 0) && vn_is_opened(vp, V_READ)) || 174*6600Sas200622 vn_is_mapped(vp, V_RDORWR)); 175*6600Sas200622 } 176*6600Sas200622 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 196*6600Sas200622 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &smb_ct); 1975772Sas200622 error = VOP_READ(vp, uiop, 0, cr, &smb_ct); 198*6600Sas200622 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &smb_ct); 1995331Samw return (error); 2005331Samw } 2015331Samw 2025331Samw int 2035331Samw smb_vop_write(vnode_t *vp, uio_t *uiop, uint32_t *flag, uint32_t *lcount, 2045772Sas200622 cred_t *cr) 2055331Samw { 2065331Samw int error; 2075331Samw int ioflag = 0; 2085331Samw 2095331Samw *lcount = uiop->uio_resid; 2105331Samw 2115331Samw if (*flag == FSSTAB_FILE_SYNC) 2125331Samw ioflag = FSYNC; 2135331Samw 2145331Samw uiop->uio_llimit = MAXOFFSET_T; 2155331Samw 216*6600Sas200622 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &smb_ct); 2175772Sas200622 error = VOP_WRITE(vp, uiop, ioflag, cr, &smb_ct); 218*6600Sas200622 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &smb_ct); 2195331Samw 2205331Samw *lcount -= uiop->uio_resid; 2215331Samw 2225331Samw return (error); 2235331Samw } 2245331Samw 2255331Samw /* 2265331Samw * smb_vop_getattr() 2275331Samw * 2285331Samw * smb_fsop_getattr()/smb_vop_getattr() should always be called from the CIFS 2295331Samw * service (instead of calling VOP_GETATTR directly) to retrieve attributes 2305331Samw * due to special processing needed for streams files. 2315331Samw * 2325331Samw * All attributes are retrieved. 2335331Samw * 2345331Samw * A named stream's attributes (as far as CIFS is concerned) are those of the 2355331Samw * unnamed (i.e. data) stream (minus the size attribute), and the size of the 2365331Samw * named stream. Though the file system may store attributes other than size 2375331Samw * with the named stream, these should not be used by CIFS for any purpose. 2385331Samw * 2395331Samw * When vp denotes a named stream, then unnamed_vp should be passed in (denoting 2405331Samw * the corresponding unnamed stream). 2415331Samw */ 2425331Samw 2435331Samw int 2445331Samw smb_vop_getattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *ret_attr, 2455772Sas200622 int flags, cred_t *cr) 2465331Samw { 2475331Samw int error; 2485331Samw vnode_t *use_vp; 2495331Samw smb_attr_t tmp_attr; 2505331Samw xvattr_t tmp_xvattr; 2515331Samw xoptattr_t *xoap = NULL; 2525331Samw 2535331Samw if (unnamed_vp) 2545331Samw use_vp = unnamed_vp; 2555331Samw else 2565331Samw use_vp = vp; 2575331Samw 2585331Samw if (vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) { 2595331Samw xva_init(&tmp_xvattr); 2605331Samw xoap = xva_getxoptattr(&tmp_xvattr); 2615331Samw 2625331Samw ASSERT(xoap); 2635331Samw 2645331Samw smb_sa_to_va_mask(ret_attr->sa_mask, 2655331Samw &tmp_xvattr.xva_vattr.va_mask); 2665331Samw 2675331Samw XVA_SET_REQ(&tmp_xvattr, XAT_READONLY); 2685331Samw XVA_SET_REQ(&tmp_xvattr, XAT_HIDDEN); 2695331Samw XVA_SET_REQ(&tmp_xvattr, XAT_SYSTEM); 2705331Samw XVA_SET_REQ(&tmp_xvattr, XAT_ARCHIVE); 2715331Samw XVA_SET_REQ(&tmp_xvattr, XAT_CREATETIME); 2725331Samw 2735331Samw if ((error = VOP_GETATTR(use_vp, (vattr_t *)&tmp_xvattr, flags, 2745772Sas200622 cr, &smb_ct)) != 0) 2755331Samw return (error); 2765331Samw 2775331Samw ret_attr->sa_vattr = tmp_xvattr.xva_vattr; 2785331Samw 2795331Samw /* 2805331Samw * Copy special attributes to ret_attr parameter 2815331Samw */ 2825331Samw 2835331Samw ret_attr->sa_dosattr = 0; 2845331Samw 2855331Samw ASSERT(tmp_xvattr.xva_vattr.va_mask & AT_XVATTR); 2865331Samw 2875331Samw xoap = xva_getxoptattr(&tmp_xvattr); 2885331Samw ASSERT(xoap); 2895331Samw 2905331Samw if (XVA_ISSET_RTN(&tmp_xvattr, XAT_READONLY)) { 2915331Samw if (xoap->xoa_readonly) 2925331Samw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_READONLY; 2935331Samw } 2945331Samw 2955331Samw if (XVA_ISSET_RTN(&tmp_xvattr, XAT_HIDDEN)) { 2965331Samw if (xoap->xoa_hidden) 2975331Samw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_HIDDEN; 2985331Samw } 2995331Samw 3005331Samw if (XVA_ISSET_RTN(&tmp_xvattr, XAT_SYSTEM)) { 3015331Samw if (xoap->xoa_system) 3025331Samw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_SYSTEM; 3035331Samw } 3045331Samw 3055331Samw if (XVA_ISSET_RTN(&tmp_xvattr, XAT_ARCHIVE)) { 3065331Samw if (xoap->xoa_archive) 3075331Samw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_ARCHIVE; 3085331Samw } 3095331Samw 3105331Samw ret_attr->sa_crtime = xoap->xoa_createtime; 3115331Samw 3125331Samw if (unnamed_vp && (ret_attr->sa_mask & SMB_AT_SIZE)) { 3135331Samw /* 3145331Samw * Retrieve stream size attribute into temporary 3155331Samw * structure, in case the underlying file system 3165331Samw * returns attributes other than the size (we do not 3175331Samw * want to have ret_attr's other fields get 3185331Samw * overwritten). 3195331Samw * 3205331Samw * Note that vp is used here, and not use_vp. 3215331Samw * Also, only AT_SIZE is needed. 3225331Samw */ 3235331Samw 3245331Samw tmp_xvattr.xva_vattr.va_mask = AT_SIZE; 3255331Samw 3265331Samw if ((error = VOP_GETATTR(vp, (vattr_t *)&tmp_xvattr, 3275772Sas200622 flags, cr, &smb_ct)) != 0) 3285331Samw return (error); 3295331Samw 3305331Samw ret_attr->sa_vattr.va_size = 3315331Samw tmp_xvattr.xva_vattr.va_size; 3325331Samw 3335331Samw } 3345331Samw 3355331Samw if (ret_attr->sa_vattr.va_type == VDIR) { 3365331Samw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY; 3375331Samw } 3385331Samw 3395331Samw return (error); 3405331Samw } 3415331Samw 3425331Samw /* 3435331Samw * Support for file systems without VFSFT_XVATTR 3445331Samw */ 3455331Samw 3465331Samw smb_sa_to_va_mask(ret_attr->sa_mask, 3475331Samw &ret_attr->sa_vattr.va_mask); 3485331Samw 3495772Sas200622 error = VOP_GETATTR(use_vp, &ret_attr->sa_vattr, flags, cr, &smb_ct); 3505331Samw 3515331Samw if (error != 0) 3525331Samw return (error); 3535331Samw 3545331Samw /* 3555331Samw * "Fake" DOS attributes and create time, filesystem doesn't support 3565331Samw * them. 3575331Samw */ 3585331Samw 3595331Samw ret_attr->sa_dosattr = 0; 3605331Samw ret_attr->sa_crtime = ret_attr->sa_vattr.va_ctime; 3615331Samw 3625331Samw if (unnamed_vp && (ret_attr->sa_mask & SMB_AT_SIZE)) { 3635331Samw /* 3645331Samw * Retrieve stream size attribute into temporary structure, 3655331Samw * in case the underlying file system returns attributes 3665331Samw * other than the size (we do not want to have ret_attr's 3675331Samw * other fields get overwritten). 3685331Samw * 3695331Samw * Note that vp is used here, and not use_vp. 3705331Samw * Also, only AT_SIZE is needed. 3715331Samw */ 3725331Samw 3735331Samw tmp_attr.sa_vattr.va_mask = AT_SIZE; 3745772Sas200622 error = VOP_GETATTR(vp, &tmp_attr.sa_vattr, flags, cr, &smb_ct); 3755331Samw 3765331Samw if (error != 0) 3775331Samw return (error); 3785331Samw 3795331Samw 3805331Samw ret_attr->sa_vattr.va_size = tmp_attr.sa_vattr.va_size; 3815331Samw } 3825331Samw 3835331Samw if (ret_attr->sa_vattr.va_type == VDIR) { 3845331Samw ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY; 3855331Samw } 3865331Samw 3875331Samw return (error); 3885331Samw } 3895331Samw 3905331Samw /* 3915331Samw * smb_vop_setattr() 3925331Samw * 3936030Sjb150015 * smb_fsop_setattr()/smb_vop_setattr() should always be used instead of 3946030Sjb150015 * VOP_SETATTR() when calling from the CIFS service, due to special processing 3956030Sjb150015 * for streams files. 3965331Samw * 3976030Sjb150015 * Streams have a size but otherwise do not have separate attributes from 3986030Sjb150015 * the (unnamed stream) file, i.e., the security and ownership of the file 3996030Sjb150015 * applies to the stream. In contrast, extended attribute files, which are 4006030Sjb150015 * used to implement streams, are independent objects with their own 4016030Sjb150015 * attributes. 4026030Sjb150015 * 4036030Sjb150015 * For compatibility with streams, we set the size on the extended attribute 4046030Sjb150015 * file and apply other attributes to the (unnamed stream) file. The one 4056030Sjb150015 * exception is that the UID and GID can be set on the stream by passing a 4066030Sjb150015 * NULL unnamed_vp, which allows callers to synchronize stream ownership 4076030Sjb150015 * with the (unnamed stream) file. 4085331Samw */ 4095331Samw 4105331Samw int 4115331Samw smb_vop_setattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *set_attr, 4125772Sas200622 int flags, cred_t *cr, boolean_t no_xvattr) 4135331Samw { 4145331Samw int error = 0; 4155331Samw int at_size = 0; 4165331Samw vnode_t *use_vp; 4175772Sas200622 xvattr_t xvattr; 4185772Sas200622 vattr_t *vap; 4195331Samw 4205331Samw if (unnamed_vp) { 4215331Samw use_vp = unnamed_vp; 4225331Samw if (set_attr->sa_mask & SMB_AT_SIZE) { 4235331Samw at_size = 1; 4245331Samw set_attr->sa_mask &= ~SMB_AT_SIZE; 4255331Samw } 4265331Samw } else { 4275331Samw use_vp = vp; 4285331Samw } 4295331Samw 4305331Samw /* 4315331Samw * The caller should not be setting sa_vattr.va_mask, 4325331Samw * but rather sa_mask. 4335331Samw */ 4345331Samw 4355331Samw set_attr->sa_vattr.va_mask = 0; 4365331Samw 4375521Sas200622 if ((no_xvattr == B_FALSE) && 4385521Sas200622 vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) { 4395331Samw 4405772Sas200622 smb_vop_setup_xvattr(set_attr, &xvattr); 4415772Sas200622 vap = (vattr_t *)&xvattr; 4425772Sas200622 } else { 4435331Samw smb_sa_to_va_mask(set_attr->sa_mask, 4445772Sas200622 &set_attr->sa_vattr.va_mask); 4455772Sas200622 vap = &set_attr->sa_vattr; 4465772Sas200622 } 4475331Samw 4485772Sas200622 if ((error = VOP_SETATTR(use_vp, vap, flags, cr, &smb_ct)) != 0) 4495772Sas200622 return (error); 4505331Samw 4515331Samw /* 4525772Sas200622 * If the size of the stream needs to be set, set it on 4535772Sas200622 * the stream file directly. (All other indicated attributes 4546030Sjb150015 * are set on the stream's unnamed stream, except under the 4556030Sjb150015 * exception described in the function header.) 4565331Samw */ 4575331Samw 4585331Samw if (at_size) { 4595331Samw /* 4605331Samw * set_attr->sa_vattr.va_size already contains the 4615331Samw * size as set by the caller 4625331Samw * 4635331Samw * Note that vp is used here, and not use_vp. 4645331Samw * Also, only AT_SIZE is needed. 4655331Samw */ 4665331Samw 4675331Samw set_attr->sa_vattr.va_mask = AT_SIZE; 4685772Sas200622 error = VOP_SETATTR(vp, &set_attr->sa_vattr, flags, cr, 4695772Sas200622 &smb_ct); 4705331Samw } 4715772Sas200622 4725331Samw return (error); 4735331Samw } 4745331Samw 4755331Samw /* 4765331Samw * smb_vop_access 4775331Samw * 4785331Samw * This is a wrapper round VOP_ACCESS. VOP_ACCESS checks the given mode 4795331Samw * against file's ACL or Unix permissions. CIFS on the other hand needs to 4805331Samw * know if the requested operation can succeed for the given object, this 4815331Samw * requires more checks in case of DELETE bit since permissions on the parent 4825331Samw * directory are important as well. Based on Windows rules if parent's ACL 4835331Samw * grant FILE_DELETE_CHILD a file can be delete regardless of the file's 4845331Samw * permissions. 4855331Samw */ 4865331Samw int 4875331Samw smb_vop_access(vnode_t *vp, int mode, int flags, vnode_t *dir_vp, cred_t *cr) 4885331Samw { 4895331Samw int error = 0; 4905331Samw 4915331Samw if (mode == 0) 4925331Samw return (0); 4935331Samw 4945331Samw if ((flags == V_ACE_MASK) && (mode & ACE_DELETE)) { 4955331Samw if (dir_vp) { 4965331Samw error = VOP_ACCESS(dir_vp, ACE_DELETE_CHILD, flags, 4975331Samw cr, NULL); 4985331Samw 4995331Samw if (error == 0) 5005331Samw mode &= ~ACE_DELETE; 5015331Samw } 5025331Samw } 5035331Samw 5045331Samw if (mode) { 5055331Samw error = VOP_ACCESS(vp, mode, flags, cr, NULL); 5065331Samw } 5075331Samw 5085331Samw return (error); 5095331Samw } 5105331Samw 5115331Samw /* 5125331Samw * smb_vop_lookup 5135331Samw * 5145331Samw * dvp: directory vnode (in) 5155331Samw * name: name of file to be looked up (in) 5165331Samw * vpp: looked-up vnode (out) 5175331Samw * od_name: on-disk name of file (out). 5185331Samw * This parameter is optional. If a pointer is passed in, it 5195331Samw * must be allocated with MAXNAMELEN bytes 5205331Samw * rootvp: vnode of the tree root (in) 5215331Samw * This parameter is always passed in non-NULL except at the time 5225331Samw * of share set up. 5235331Samw */ 5245331Samw 5255331Samw int 5266139Sjb150015 smb_vop_lookup( 5276139Sjb150015 vnode_t *dvp, 5286139Sjb150015 char *name, 5296139Sjb150015 vnode_t **vpp, 5306139Sjb150015 char *od_name, 5316139Sjb150015 int flags, 5326139Sjb150015 vnode_t *rootvp, 5336139Sjb150015 cred_t *cr) 5345331Samw { 5355331Samw int error = 0; 5365331Samw int option_flags = 0; 5375331Samw pathname_t rpn; 5385331Samw 5395331Samw if (*name == '\0') 5405331Samw return (EINVAL); 5415331Samw 5425331Samw ASSERT(vpp); 5435331Samw *vpp = NULL; 5445331Samw 5455331Samw if ((name[0] == '.') && (name[1] == '.') && (name[2] == 0)) { 5465331Samw if (rootvp && (dvp == rootvp)) { 5475331Samw VN_HOLD(dvp); 5485331Samw *vpp = dvp; 5495331Samw return (0); 5505331Samw } 5515331Samw 5525331Samw if (dvp->v_flag & VROOT) { 5535331Samw vfs_t *vfsp; 5545331Samw vnode_t *cvp = dvp; 5555331Samw 5565331Samw /* 5575331Samw * Set dvp and check for races with forced unmount 5585331Samw * (see lookuppnvp()) 5595331Samw */ 5605331Samw 5615331Samw vfsp = cvp->v_vfsp; 5625331Samw vfs_rlock_wait(vfsp); 5635331Samw if (((dvp = cvp->v_vfsp->vfs_vnodecovered) == NULL) || 5645331Samw (cvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)) { 5655331Samw vfs_unlock(vfsp); 5665331Samw return (EIO); 5675331Samw } 5685331Samw vfs_unlock(vfsp); 5695331Samw } 5705331Samw } 5715331Samw 5725331Samw 5735331Samw 5745331Samw if (flags & SMB_IGNORE_CASE) 5755331Samw option_flags = FIGNORECASE; 5765331Samw 5775331Samw pn_alloc(&rpn); 5785331Samw 5795331Samw error = VOP_LOOKUP(dvp, name, vpp, NULL, option_flags, NULL, cr, 5805772Sas200622 &smb_ct, NULL, &rpn); 5815331Samw 5825331Samw if ((error == 0) && od_name) { 5835331Samw bzero(od_name, MAXNAMELEN); 5845331Samw if (option_flags == FIGNORECASE) 5855331Samw (void) strlcpy(od_name, rpn.pn_buf, MAXNAMELEN); 5865331Samw else 5875331Samw (void) strlcpy(od_name, name, MAXNAMELEN); 5885331Samw } 5895331Samw 5905331Samw pn_free(&rpn); 5915331Samw return (error); 5925331Samw } 5935331Samw 5945331Samw int 5955331Samw smb_vop_create(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp, 5965772Sas200622 int flags, cred_t *cr, vsecattr_t *vsap) 5975772Sas200622 { 5985772Sas200622 int error; 5995772Sas200622 int option_flags = 0; 6005772Sas200622 xvattr_t xvattr; 6015772Sas200622 vattr_t *vap; 6025772Sas200622 6035772Sas200622 if (flags & SMB_IGNORE_CASE) 6045772Sas200622 option_flags = FIGNORECASE; 6055772Sas200622 6065772Sas200622 attr->sa_vattr.va_mask = 0; 6075772Sas200622 6085772Sas200622 if (vfs_has_feature(dvp->v_vfsp, VFSFT_XVATTR)) { 6095772Sas200622 smb_vop_setup_xvattr(attr, &xvattr); 6105772Sas200622 vap = (vattr_t *)&xvattr; 6115772Sas200622 } else { 6125772Sas200622 smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask); 6135772Sas200622 vap = &attr->sa_vattr; 6145772Sas200622 } 6155772Sas200622 6165772Sas200622 error = VOP_CREATE(dvp, name, vap, EXCL, attr->sa_vattr.va_mode, 6175772Sas200622 vpp, cr, option_flags, &smb_ct, vsap); 6185772Sas200622 6195772Sas200622 return (error); 6205772Sas200622 } 6215772Sas200622 6225772Sas200622 int 6235772Sas200622 smb_vop_remove(vnode_t *dvp, char *name, int flags, cred_t *cr) 6245331Samw { 6255331Samw int error; 6265331Samw int option_flags = 0; 6275331Samw 6285331Samw if (flags & SMB_IGNORE_CASE) 6295331Samw option_flags = FIGNORECASE; 6305331Samw 6315772Sas200622 error = VOP_REMOVE(dvp, name, cr, &smb_ct, option_flags); 6325331Samw 6335331Samw return (error); 6345331Samw } 6355331Samw 6365331Samw /* 6375331Samw * smb_vop_rename() 6385331Samw * 6395331Samw * The rename is for files in the same tree (identical TID) only. 6405331Samw */ 6415331Samw 6425331Samw int 6435331Samw smb_vop_rename(vnode_t *from_dvp, char *from_name, vnode_t *to_dvp, 6445772Sas200622 char *to_name, int flags, cred_t *cr) 6455331Samw { 6465331Samw int error; 6475331Samw int option_flags = 0; 6485331Samw 6495331Samw 6505331Samw if (flags & SMB_IGNORE_CASE) 6515331Samw option_flags = FIGNORECASE; 6525331Samw 6535331Samw error = VOP_RENAME(from_dvp, from_name, to_dvp, to_name, cr, 6545772Sas200622 &smb_ct, option_flags); 6555331Samw 6565331Samw return (error); 6575331Samw } 6585331Samw 6595331Samw int 6605331Samw smb_vop_mkdir(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp, 6615772Sas200622 int flags, cred_t *cr, vsecattr_t *vsap) 6625331Samw { 6635331Samw int error; 6645331Samw int option_flags = 0; 6655331Samw 6665331Samw 6675331Samw 6685331Samw if (flags & SMB_IGNORE_CASE) 6695331Samw option_flags = FIGNORECASE; 6705331Samw 6715331Samw smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask); 6725331Samw 6735772Sas200622 error = VOP_MKDIR(dvp, name, &attr->sa_vattr, vpp, cr, &smb_ct, 6745331Samw option_flags, vsap); 6755331Samw 6765331Samw return (error); 6775331Samw } 6785331Samw 6795331Samw /* 6805331Samw * smb_vop_rmdir() 6815331Samw * 6825331Samw * Only simple rmdir supported, consistent with NT semantics 6835331Samw * (can only remove an empty directory). 6845331Samw * 6855331Samw */ 6865331Samw 6875331Samw int 6885772Sas200622 smb_vop_rmdir(vnode_t *dvp, char *name, int flags, cred_t *cr) 6895331Samw { 6905331Samw int error; 6915331Samw int option_flags = 0; 6925331Samw 6935331Samw if (flags & SMB_IGNORE_CASE) 6945331Samw option_flags = FIGNORECASE; 6955331Samw 6965331Samw /* 6975331Samw * Comments adapted from rfs_rmdir(). 6985331Samw * 6995331Samw * VOP_RMDIR now takes a new third argument (the current 7005331Samw * directory of the process). That's because rmdir 7015331Samw * wants to return EINVAL if one tries to remove ".". 7025331Samw * Of course, SMB servers do not know what their 7035331Samw * clients' current directories are. We fake it by 7045331Samw * supplying a vnode known to exist and illegal to 7055331Samw * remove. 7065331Samw */ 7075331Samw 7085772Sas200622 error = VOP_RMDIR(dvp, name, rootdir, cr, &smb_ct, option_flags); 7095331Samw return (error); 7105331Samw } 7115331Samw 7125331Samw int 7135772Sas200622 smb_vop_commit(vnode_t *vp, cred_t *cr) 7145772Sas200622 { 7155772Sas200622 return (VOP_FSYNC(vp, 1, cr, &smb_ct)); 7165772Sas200622 } 7175772Sas200622 7185772Sas200622 void 7195772Sas200622 smb_vop_setup_xvattr(smb_attr_t *smb_attr, xvattr_t *xvattr) 7205331Samw { 7215772Sas200622 xoptattr_t *xoap = NULL; 7225772Sas200622 uint_t xva_mask; 7235772Sas200622 7245772Sas200622 /* 7255772Sas200622 * Initialize xvattr, including bzero 7265772Sas200622 */ 7275772Sas200622 xva_init(xvattr); 7285772Sas200622 xoap = xva_getxoptattr(xvattr); 7295772Sas200622 7305772Sas200622 ASSERT(xoap); 7315772Sas200622 7325772Sas200622 /* 7335772Sas200622 * Copy caller-specified classic attributes to xvattr. 7345772Sas200622 * First save xvattr's mask (set in xva_init()), which 7355772Sas200622 * contains AT_XVATTR. This is |'d in later if needed. 7365772Sas200622 */ 7375772Sas200622 7385772Sas200622 xva_mask = xvattr->xva_vattr.va_mask; 7395772Sas200622 xvattr->xva_vattr = smb_attr->sa_vattr; 7405772Sas200622 7415772Sas200622 smb_sa_to_va_mask(smb_attr->sa_mask, &xvattr->xva_vattr.va_mask); 7425772Sas200622 7435772Sas200622 /* 7445772Sas200622 * Do not set ctime (only the file system can do it) 7455772Sas200622 */ 7465772Sas200622 7475772Sas200622 xvattr->xva_vattr.va_mask &= ~AT_CTIME; 7485772Sas200622 7495772Sas200622 if (smb_attr->sa_mask & SMB_AT_DOSATTR) { 7505772Sas200622 7515772Sas200622 /* 7525772Sas200622 * "|" in the original xva_mask, which contains 7535772Sas200622 * AT_XVATTR 7545772Sas200622 */ 7555772Sas200622 7565772Sas200622 xvattr->xva_vattr.va_mask |= xva_mask; 7575772Sas200622 7585772Sas200622 XVA_SET_REQ(xvattr, XAT_ARCHIVE); 7595772Sas200622 XVA_SET_REQ(xvattr, XAT_SYSTEM); 7605772Sas200622 XVA_SET_REQ(xvattr, XAT_READONLY); 7615772Sas200622 XVA_SET_REQ(xvattr, XAT_HIDDEN); 7625772Sas200622 7635772Sas200622 /* 7645772Sas200622 * smb_attr->sa_dosattr: If a given bit is not set, 7655772Sas200622 * that indicates that the corresponding field needs 7665772Sas200622 * to be updated with a "0" value. This is done 7675772Sas200622 * implicitly as the xoap->xoa_* fields were bzero'd. 7685772Sas200622 */ 7695772Sas200622 7705772Sas200622 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_ARCHIVE) 7715772Sas200622 xoap->xoa_archive = 1; 7725772Sas200622 7735772Sas200622 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_SYSTEM) 7745772Sas200622 xoap->xoa_system = 1; 7755772Sas200622 7765772Sas200622 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_READONLY) 7775772Sas200622 xoap->xoa_readonly = 1; 7785772Sas200622 7795772Sas200622 if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_HIDDEN) 7805772Sas200622 xoap->xoa_hidden = 1; 7815772Sas200622 } 7825772Sas200622 7835772Sas200622 if (smb_attr->sa_mask & SMB_AT_CRTIME) { 7845772Sas200622 /* 7855772Sas200622 * "|" in the original xva_mask, which contains 7865772Sas200622 * AT_XVATTR 7875772Sas200622 */ 7885772Sas200622 7895772Sas200622 xvattr->xva_vattr.va_mask |= xva_mask; 7905772Sas200622 XVA_SET_REQ(xvattr, XAT_CREATETIME); 7915772Sas200622 xoap->xoa_createtime = smb_attr->sa_crtime; 7925772Sas200622 } 7935331Samw } 7945331Samw 7955772Sas200622 7965331Samw /* 7975331Samw * smb_vop_readdir() 7985331Samw * 7995331Samw * Upon return, the "name" field will contain either the on-disk name or, if 8005331Samw * it needs mangling or has a case-insensitive collision, the mangled 8015331Samw * "shortname." 8025331Samw * 8035331Samw * vpp is an optional parameter. If non-NULL, it will contain a pointer to 8045331Samw * the vnode for the name that is looked up (the vnode will be returned held). 8055331Samw * 8065331Samw * od_name is an optional parameter (NULL can be passed if the on-disk name 8075331Samw * is not needed by the caller). 8085331Samw */ 8095331Samw 8105331Samw int 8115331Samw smb_vop_readdir(vnode_t *dvp, uint32_t *cookiep, char *name, int *namelen, 8125772Sas200622 ino64_t *inop, vnode_t **vpp, char *od_name, int flags, cred_t *cr) 8135331Samw { 8145331Samw int num_bytes; 8155331Samw int error = 0; 8165331Samw char *dirbuf = NULL; 8175331Samw 8185331Samw ASSERT(dvp); 8195331Samw ASSERT(cookiep); 8205331Samw ASSERT(name); 8215331Samw ASSERT(namelen); 8225331Samw ASSERT(inop); 8235331Samw ASSERT(cr); 8245331Samw 8255331Samw if (dvp->v_type != VDIR) { 8265331Samw *namelen = 0; 8275331Samw return (ENOTDIR); 8285331Samw } 8295331Samw 8305331Samw if (vpp) 8315331Samw *vpp = NULL; 8325331Samw 8335331Samw dirbuf = kmem_zalloc(SMB_MINLEN_RDDIR_BUF, KM_SLEEP); 8345331Samw num_bytes = SMB_MINLEN_RDDIR_BUF; 8355331Samw 8365331Samw /* 8375331Samw * The goal is to retrieve the first valid entry from *cookiep 8385331Samw * forward. smb_vop_readdir_readpage() collects an 8395331Samw * SMB_MINLEN_RDDIR_BUF-size "page" of directory entry information. 8405331Samw * smb_vop_readdir_entry() attempts to find the first valid entry 8415331Samw * in that page. 8425331Samw */ 8435331Samw 8445331Samw while ((error = smb_vop_readdir_readpage(dvp, dirbuf, *cookiep, 8455772Sas200622 &num_bytes, cr, flags)) == 0) { 8465331Samw 8475331Samw if (num_bytes <= 0) 8485331Samw break; 8495331Samw 8505331Samw name[0] = '\0'; 8515331Samw 8525331Samw error = smb_vop_readdir_entry(dvp, cookiep, name, namelen, 8536139Sjb150015 inop, vpp, od_name, flags, cr, dirbuf, num_bytes); 8545331Samw 8555331Samw if (error) 8565331Samw break; 8575331Samw 8585331Samw if (*name) 8595331Samw break; 8605331Samw 8615331Samw bzero(dirbuf, SMB_MINLEN_RDDIR_BUF); 8625331Samw num_bytes = SMB_MINLEN_RDDIR_BUF; 8635331Samw } 8645331Samw 8655331Samw 8665331Samw if (error) { 8675331Samw kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 8685331Samw *namelen = 0; 8695331Samw return (error); 8705331Samw } 8715331Samw 8725331Samw if (num_bytes == 0) { /* EOF */ 8735331Samw kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 8745331Samw *cookiep = SMB_EOF; 8755331Samw *namelen = 0; 8765331Samw return (0); 8775331Samw } 8785331Samw 8795331Samw kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 8805331Samw return (0); 8815331Samw } 8825331Samw 8835331Samw /* 8845331Samw * smb_vop_readdir_readpage() 8855331Samw * 8865331Samw * Collects an SMB_MINLEN_RDDIR_BUF "page" of directory entries. (The 8875331Samw * directory entries are returned in an fs-independent format by the 8885331Samw * underlying file system. That is, the "page" of information returned is 8895331Samw * not literally stored on-disk in the format returned.) 8905331Samw * 8915331Samw * Much of the following is borrowed from getdents64() 8925331Samw * 8935331Samw * MAXGETDENTS_SIZE is defined in getdents.c 8945331Samw */ 8955331Samw 8965331Samw #define MAXGETDENTS_SIZE (64 * 1024) 8975331Samw 8985331Samw static int 8995331Samw smb_vop_readdir_readpage(vnode_t *vp, void *buf, uint32_t offset, int *count, 9005772Sas200622 cred_t *cr, int flags) 9015331Samw { 9025331Samw int error = 0; 9035331Samw int rdirent_flags = 0; 9045331Samw int sink; 9055331Samw struct uio auio; 9065331Samw struct iovec aiov; 9075331Samw 9085331Samw if (vp->v_type != VDIR) 9095331Samw return (ENOTDIR); 9105331Samw 9115331Samw /* entflags not working for streams so don't try to use them */ 9125331Samw if (!(flags & SMB_STREAM_RDDIR) && 9135331Samw (vfs_has_feature(vp->v_vfsp, VFSFT_DIRENTFLAGS))) { 9145331Samw /* 9155331Samw * Setting V_RDDIR_ENTFLAGS will cause the buffer to 9165331Samw * be filled with edirent_t structures (instead of 9175331Samw * dirent64_t structures). 9185331Samw */ 9195331Samw rdirent_flags = V_RDDIR_ENTFLAGS; 9205331Samw 9215331Samw if (*count < sizeof (edirent_t)) 9225331Samw return (EINVAL); 9235331Samw } else { 9245331Samw if (*count < sizeof (dirent64_t)) 9255331Samw return (EINVAL); 9265331Samw } 9275331Samw 9285331Samw if (*count > MAXGETDENTS_SIZE) 9295331Samw *count = MAXGETDENTS_SIZE; 9305331Samw 9315331Samw aiov.iov_base = buf; 9325331Samw aiov.iov_len = *count; 9335331Samw auio.uio_iov = &aiov; 9345331Samw auio.uio_iovcnt = 1; 9355331Samw auio.uio_loffset = (uint64_t)offset; 9365331Samw auio.uio_segflg = UIO_SYSSPACE; 9375331Samw auio.uio_resid = *count; 9385331Samw auio.uio_fmode = 0; 9395331Samw 940*6600Sas200622 (void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, &smb_ct); 9415772Sas200622 error = VOP_READDIR(vp, &auio, cr, &sink, &smb_ct, rdirent_flags); 942*6600Sas200622 VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, &smb_ct); 9435331Samw 9445331Samw if (error) { 9455331Samw if (error == ENOENT) { 9465331Samw /* Fake EOF if offset is bad due to dropping of lock */ 9475331Samw *count = 0; 9485331Samw return (0); 9495331Samw } else { 9505331Samw return (error); 9515331Samw } 9525331Samw } 9535331Samw 9545331Samw /* 9555331Samw * Windows cannot handle an offset > SMB_EOF. 9565331Samw * Pretend we are at EOF. 9575331Samw */ 9585331Samw 9595331Samw if (auio.uio_loffset > SMB_EOF) { 9605331Samw *count = 0; 9615331Samw return (0); 9625331Samw } 9635331Samw 9645331Samw *count = *count - auio.uio_resid; 9655331Samw return (0); 9665331Samw } 9675331Samw 9685331Samw /* 9695331Samw * smb_vop_readdir_entry() 9705331Samw * 9715331Samw * This function retrieves the first valid entry from the 9725331Samw * SMB_MINLEN_RDDIR_BUF-sized buffer returned by smb_vop_readdir_readpage() 9735331Samw * to smb_vop_readdir(). 9745331Samw * 9755331Samw * Both dirent64_t and edirent_t structures need to be handled. The former is 9765331Samw * needed for file systems that do not support VFSFT_DIRENTFLAGS. The latter 9775331Samw * is required for proper handling of case collisions on file systems that 9785331Samw * support case-insensitivity. edirent_t structures are also used for 9795331Samw * case-sensitive file systems if VFSFT_DIRENTFLAGS is supported. 9805331Samw */ 9815331Samw 9825331Samw static int 9836139Sjb150015 smb_vop_readdir_entry( 9846139Sjb150015 vnode_t *dvp, 9856139Sjb150015 uint32_t *cookiep, 9866139Sjb150015 char *name, 9876139Sjb150015 int *namelen, 9886139Sjb150015 ino64_t *inop, 9896139Sjb150015 vnode_t **vpp, 9906139Sjb150015 char *od_name, 9916139Sjb150015 int flags, 9926139Sjb150015 cred_t *cr, 9936139Sjb150015 char *dirbuf, 9946139Sjb150015 int num_bytes) 9955331Samw { 9965331Samw uint32_t next_cookie; 9975331Samw int ebufsize; 9985331Samw int error = 0; 9995331Samw int len; 10005331Samw int rc; 10015331Samw char shortname[MANGLE_NAMELEN]; 10025331Samw char name83[MANGLE_NAMELEN]; 10035331Samw char *ebuf = NULL; 10045331Samw edirent_t *edp; 10055331Samw dirent64_t *dp = NULL; 10065331Samw vnode_t *vp = NULL; 10075331Samw 10085331Samw ASSERT(dirbuf); 10095331Samw 10105331Samw /* 10115331Samw * Use edirent_t structure for both 10125331Samw * entflags not working for streams so don't try to use them 10135331Samw */ 10145331Samw if (!(flags & SMB_STREAM_RDDIR) && 10155331Samw (vfs_has_feature(dvp->v_vfsp, VFSFT_DIRENTFLAGS))) { 10165331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 10175331Samw edp = (edirent_t *)dirbuf; 10185331Samw } else { 10195331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 10205331Samw dp = (dirent64_t *)dirbuf; 10215331Samw ebufsize = EDIRENT_RECLEN(MAXNAMELEN); 10225331Samw ebuf = kmem_zalloc(ebufsize, KM_SLEEP); 10235331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 10245331Samw edp = (edirent_t *)ebuf; 10255331Samw } 10265331Samw 10275331Samw while (edp) { 10285331Samw if (dp) 10295331Samw DP_TO_EDP(dp, edp); 10305331Samw 10315331Samw next_cookie = (uint32_t)edp->ed_off; 10325331Samw if (edp->ed_ino == 0) { 10335331Samw *cookiep = next_cookie; 10345331Samw 10355331Samw if (dp) { 10365331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 10375331Samw DP_ADVANCE(dp, dirbuf, num_bytes); 10385331Samw if (dp == NULL) 10395331Samw edp = NULL; 10405331Samw } else { 10415331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 10425331Samw EDP_ADVANCE(edp, dirbuf, num_bytes); 10435331Samw } 10445331Samw continue; 10455331Samw } 10465331Samw 10475331Samw len = strlen(edp->ed_name); 10485331Samw 10495331Samw if (*namelen < len) { 10505331Samw *namelen = 0; 10515331Samw 10525331Samw if (ebuf) 10535331Samw kmem_free(ebuf, ebufsize); 10545331Samw 10555331Samw return (EOVERFLOW); 10565331Samw } 10575331Samw 10585331Samw /* 10595331Samw * Do not pass SMB_IGNORE_CASE to smb_vop_lookup 10605331Samw */ 10615331Samw 10625331Samw error = smb_vop_lookup(dvp, edp->ed_name, vpp ? vpp : &vp, 10635772Sas200622 od_name, 0, NULL, cr); 10645331Samw 10655331Samw if (error) { 10665331Samw if (error == ENOENT) { 10675331Samw *cookiep = (uint32_t)next_cookie; 10685331Samw 10695331Samw if (dp) { 10705331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 10715331Samw DP_ADVANCE(dp, dirbuf, num_bytes); 10725331Samw if (dp == NULL) 10735331Samw edp = NULL; 10745331Samw } else { 10755331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 10765331Samw EDP_ADVANCE(edp, dirbuf, num_bytes); 10775331Samw } 10785331Samw continue; 10795331Samw } 10805331Samw 10815331Samw 10825331Samw *namelen = 0; 10835331Samw 10845331Samw if (ebuf) 10855331Samw kmem_free(ebuf, ebufsize); 10865331Samw 10875331Samw return (error); 10885331Samw } 10895331Samw 10905331Samw if ((flags & SMB_IGNORE_CASE) && ED_CASE_CONFLICTS(edp)) { 10915331Samw rc = smb_mangle_name(edp->ed_ino, edp->ed_name, 10925331Samw shortname, name83, 1); 10935331Samw 10945331Samw if (rc == 1) { /* success */ 10955331Samw (void) strlcpy(name, shortname, *namelen + 1); 10965331Samw *namelen = strlen(shortname); 10975331Samw } else { 10985331Samw (void) strlcpy(name, edp->ed_name, 10995331Samw *namelen + 1); 11005331Samw name[*namelen] = '\0'; 11015331Samw } 11025331Samw 11035331Samw } else { 11045331Samw (void) strlcpy(name, edp->ed_name, *namelen + 1); 11055331Samw *namelen = len; 11065331Samw } 11075331Samw 11085331Samw if (vpp == NULL) 11095331Samw VN_RELE(vp); 11105331Samw 11115331Samw if (inop) 11125331Samw *inop = edp->ed_ino; 11135331Samw 11145331Samw *cookiep = (uint32_t)next_cookie; 11155331Samw break; 11165331Samw } 11175331Samw 11185331Samw if (ebuf) 11195331Samw kmem_free(ebuf, ebufsize); 11205331Samw 11215331Samw return (error); 11225331Samw } 11235331Samw 11245331Samw /* 11255331Samw * smb_sa_to_va_mask 11265331Samw * 11275331Samw * Set va_mask by running through the SMB_AT_* #define's and 11285331Samw * setting those bits that correspond to the SMB_AT_* bits 11295331Samw * set in sa_mask. 11305331Samw */ 11315331Samw 11325331Samw void 11335331Samw smb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp) 11345331Samw { 11355331Samw int i; 11365331Samw uint_t smask; 11375331Samw 11385331Samw smask = (sa_mask); 11395331Samw for (i = SMB_AT_TYPE; (i < SMB_AT_MAX) && (smask != 0); ++i) { 11405331Samw if (smask & 1) 11415331Samw *(va_maskp) |= smb_attrmap[i]; 11425331Samw 11435331Samw smask >>= 1; 11445331Samw } 11455331Samw } 11465331Samw 11475331Samw /* 11485331Samw * smb_vop_getdents() 11495331Samw * 11505331Samw * Upon success, the smb_node corresponding to each entry returned will 11515331Samw * have a reference taken on it. These will be released in 11525331Samw * smb_trans2_find_get_dents(). 11535331Samw * 11545331Samw * If an error is returned from this routine, a list of already processed 11555331Samw * entries will be returned. The smb_nodes corresponding to these entries 11565331Samw * will be referenced, and will be released in smb_trans2_find_get_dents(). 11575331Samw * 11585331Samw * The returned dp->d_name field will contain either the on-disk name or, if 11595331Samw * it needs mangling or has a case-insensitive collision, the mangled 11605331Samw * "shortname." In this case, the on-disk name can be retrieved from the 11615331Samw * smb_node's od_name (the smb_node is passed to smb_gather_dents_info()). 11625331Samw */ 11635331Samw 11645331Samw int /*ARGSUSED*/ 11655331Samw smb_vop_getdents( 11665331Samw smb_node_t *dir_snode, 11675331Samw uint32_t *cookiep, 11685331Samw uint64_t *verifierp, 11695331Samw int32_t *dircountp, 11705331Samw char *arg, 11715331Samw char *pattern, 11725331Samw uint32_t flags, 11735331Samw smb_request_t *sr, 11745772Sas200622 cred_t *cr) 11755331Samw { 11765331Samw int error = 0; 11775331Samw int maxentries; 11785331Samw int num_bytes; 11795331Samw int resid; 11805331Samw char *dirbuf = NULL; 11815331Samw vnode_t *dvp; 11825331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 11835331Samw smb_dent_info_hdr_t *ihdr = (smb_dent_info_hdr_t *)arg; 11845331Samw 11855331Samw dvp = dir_snode->vp; 11865331Samw 11875331Samw resid = ihdr->uio.uio_resid; 11885331Samw maxentries = resid / SMB_MAX_DENT_INFO_SIZE; 11895331Samw 11905331Samw bzero(ihdr->iov->iov_base, resid); 11915331Samw 11925331Samw dirbuf = kmem_alloc(SMB_MINLEN_RDDIR_BUF, KM_SLEEP); 11935331Samw 11945331Samw while (maxentries) { 11955331Samw 11965331Samw bzero(dirbuf, SMB_MINLEN_RDDIR_BUF); 11975331Samw 11985331Samw num_bytes = SMB_MINLEN_RDDIR_BUF; 11995331Samw error = smb_vop_readdir_readpage(dvp, dirbuf, *cookiep, 12005772Sas200622 &num_bytes, cr, flags); 12015331Samw 12025331Samw if (error || (num_bytes <= 0)) 12035331Samw break; 12045331Samw 12055331Samw error = smb_vop_getdents_entries(dir_snode, cookiep, dircountp, 12065772Sas200622 arg, flags, sr, cr, dirbuf, &maxentries, num_bytes, 12075331Samw pattern); 12085331Samw 12095331Samw if (error) 12105331Samw goto out; 12115331Samw } 12125331Samw 12135331Samw if (num_bytes < 0) { 12145331Samw error = -1; 12155331Samw } else if (num_bytes == 0) { 12165331Samw *cookiep = SMB_EOF; 12175331Samw error = 0; 12185331Samw } else { 12195331Samw error = 0; 12205331Samw } 12215331Samw 12225331Samw out: 12235331Samw if (dirbuf) 12245331Samw kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF); 12255331Samw 12265331Samw return (error); 12275331Samw } 12285331Samw 12295331Samw /* 12305331Samw * smb_vop_getdents_entries() 12315331Samw * 12325331Samw * This function retrieves names from the SMB_MINLEN_RDDIR_BUF-sized buffer 12335331Samw * returned by smb_vop_readdir_readpage() to smb_vop_getdents(). 12345331Samw * 12355331Samw * Both dirent64_t and edirent_t structures need to be handled. The former is 12365331Samw * needed for file systems that do not support VFSFT_DIRENTFLAGS. The latter 12375331Samw * is required for properly handling case collisions on file systems that 12385331Samw * support case-insensitivity. edirent_t is also used on case-sensitive 12395331Samw * file systems where VFSFT_DIRENTFLAGS is available. 12405331Samw */ 12415331Samw 12425331Samw static int 12435331Samw smb_vop_getdents_entries( 12445331Samw smb_node_t *dir_snode, 12455331Samw uint32_t *cookiep, 12465331Samw int32_t *dircountp, 12475331Samw char *arg, 12485331Samw uint32_t flags, 12496139Sjb150015 smb_request_t *sr, 12505331Samw cred_t *cr, 12515331Samw char *dirbuf, 12525331Samw int *maxentries, 12535331Samw int num_bytes, 12545331Samw char *pattern) 12555331Samw { 12565331Samw uint32_t next_cookie; 12575331Samw int ebufsize; 12585331Samw char *tmp_name; 12595331Samw int error; 12605331Samw int rc; 12615331Samw char shortname[MANGLE_NAMELEN]; 12625331Samw char name83[MANGLE_NAMELEN]; 12635331Samw char *ebuf = NULL; 12645331Samw dirent64_t *dp = NULL; 12655331Samw edirent_t *edp; 12665331Samw smb_node_t *ret_snode; 12675331Samw smb_attr_t ret_attr; 12685331Samw vnode_t *dvp; 12695331Samw vnode_t *fvp; 12705331Samw 12715331Samw ASSERT(dirbuf); 12725331Samw 12735331Samw dvp = dir_snode->vp; 12745331Samw 12755331Samw if (vfs_has_feature(dvp->v_vfsp, VFSFT_DIRENTFLAGS)) { 12765331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 12775331Samw edp = (edirent_t *)dirbuf; 12785331Samw } else { 12795331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 12805331Samw dp = (dirent64_t *)dirbuf; 12815331Samw ebufsize = EDIRENT_RECLEN(MAXNAMELEN); 12825331Samw ebuf = kmem_zalloc(ebufsize, KM_SLEEP); 12835331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 12845331Samw edp = (edirent_t *)ebuf; 12855331Samw } 12865331Samw 12875331Samw while (edp) { 12885331Samw if (dp) 12895331Samw DP_TO_EDP(dp, edp); 12905331Samw 12915331Samw if (*maxentries == 0) 12925331Samw break; 12935331Samw 12945331Samw next_cookie = (uint32_t)edp->ed_off; 12955331Samw 12965331Samw if (edp->ed_ino == 0) { 12975331Samw *cookiep = next_cookie; 12985331Samw if (dp) { 12995331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 13005331Samw DP_ADVANCE(dp, dirbuf, num_bytes); 13015331Samw if (dp == NULL) 13025331Samw edp = NULL; 13035331Samw } else { 13045331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 13055331Samw EDP_ADVANCE(edp, dirbuf, num_bytes); 13065331Samw } 13075331Samw continue; 13085331Samw } 13095331Samw 13105331Samw error = smb_vop_lookup(dvp, edp->ed_name, &fvp, 13115772Sas200622 NULL, 0, NULL, cr); 13125331Samw 13135331Samw if (error) { 13145331Samw if (error == ENOENT) { 13155331Samw *cookiep = next_cookie; 13165331Samw if (dp) { 13175331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 13185331Samw DP_ADVANCE(dp, dirbuf, 13195331Samw num_bytes); 13205331Samw if (dp == NULL) 13215331Samw edp = NULL; 13225331Samw } else { 13235331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 13245331Samw EDP_ADVANCE(edp, dirbuf, 13255331Samw num_bytes); 13265331Samw } 13275331Samw continue; 13285331Samw } 13295331Samw if (ebuf) 13305331Samw kmem_free(ebuf, ebufsize); 13315331Samw 13325331Samw return (error); 13335331Samw } 13345331Samw 13355331Samw ret_snode = smb_node_lookup(sr, NULL, cr, fvp, 13365331Samw edp->ed_name, dir_snode, NULL, &ret_attr); 13375331Samw 13385331Samw if (ret_snode == NULL) { 13395331Samw VN_RELE(fvp); 13405331Samw 13415331Samw if (ebuf) 13425331Samw kmem_free(ebuf, ebufsize); 13435331Samw 13445331Samw return (ENOMEM); 13455331Samw } 13465331Samw 13475331Samw if (smb_match_name(edp->ed_ino, edp->ed_name, shortname, 13485331Samw name83, pattern, (flags & SMB_IGNORE_CASE))) { 13495331Samw 13505331Samw tmp_name = edp->ed_name; 13515331Samw 13525331Samw if ((flags & SMB_IGNORE_CASE) && 13535331Samw ED_CASE_CONFLICTS(edp)) { 13545331Samw rc = smb_mangle_name(edp->ed_ino, edp->ed_name, 13555331Samw shortname, name83, 1); 13565331Samw if (rc == 1) 13575331Samw tmp_name = shortname; 13585331Samw } else { 13595331Samw rc = smb_mangle_name(edp->ed_ino, edp->ed_name, 13605331Samw shortname, name83, 0); 13615331Samw } 13625331Samw 13635331Samw if (rc != 1) { 13645331Samw (void) strlcpy(shortname, edp->ed_name, 13655331Samw MANGLE_NAMELEN); 13665331Samw (void) strlcpy(name83, edp->ed_name, 13675331Samw MANGLE_NAMELEN); 13685331Samw shortname[MANGLE_NAMELEN - 1] = '\0'; 13695331Samw name83[MANGLE_NAMELEN - 1] = '\0'; 13705331Samw } 13715331Samw 13725331Samw error = smb_gather_dents_info(arg, edp->ed_ino, 13735331Samw strlen(tmp_name), tmp_name, next_cookie, dircountp, 13745331Samw &ret_attr, ret_snode, shortname, name83); 13755331Samw 13765331Samw if (error > 0) { 13775331Samw if (ebuf) 13785331Samw kmem_free(ebuf, ebufsize); 13795331Samw return (error); 13805331Samw } 13815331Samw 13825331Samw /* 13835331Samw * Treat errors from smb_gather_dents_info() that are 13845331Samw * < 0 the same as EOF. 13855331Samw */ 13865331Samw if (error < 0) { 13875331Samw if (ebuf) 13885331Samw kmem_free(ebuf, ebufsize); 13895331Samw *maxentries = 0; 13905331Samw return (0); 13915331Samw } 13925331Samw (*maxentries)--; 13935331Samw } else { 13945331Samw smb_node_release(ret_snode); 13955331Samw } 13965331Samw 13975331Samw *cookiep = next_cookie; 13985331Samw 13995331Samw if (dp) { 14005331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 14015331Samw DP_ADVANCE(dp, dirbuf, num_bytes); 14025331Samw if (dp == NULL) 14035331Samw edp = NULL; 14045331Samw } else { 14055331Samw /*LINTED E_BAD_PTR_CAST_ALIGN*/ 14065331Samw EDP_ADVANCE(edp, dirbuf, num_bytes); 14075331Samw } 14085331Samw } 14095331Samw 14105331Samw if (ebuf) 14115331Samw kmem_free(ebuf, ebufsize); 14125331Samw 14135331Samw return (0); 14145331Samw } 14155331Samw 14165331Samw /* 14175331Samw * smb_vop_stream_lookup() 14185331Samw * 14195331Samw * The name returned in od_name is the on-disk name of the stream with the 14205331Samw * SMB_STREAM_PREFIX stripped off. od_name should be allocated to MAXNAMELEN 14215331Samw * by the caller. 14225331Samw */ 14235331Samw 14245331Samw int 14256139Sjb150015 smb_vop_stream_lookup( 14266139Sjb150015 vnode_t *fvp, 14276139Sjb150015 char *stream_name, 14286139Sjb150015 vnode_t **vpp, 14296139Sjb150015 char *od_name, 14306139Sjb150015 vnode_t **xattrdirvpp, 14316139Sjb150015 int flags, 14326139Sjb150015 vnode_t *rootvp, 14336139Sjb150015 cred_t *cr) 14345331Samw { 14355331Samw char *solaris_stream_name; 14365331Samw char *name; 14375331Samw int error; 14385331Samw 14395331Samw if ((error = smb_vop_lookup_xattrdir(fvp, xattrdirvpp, 14405772Sas200622 LOOKUP_XATTR | CREATE_XATTR_DIR, cr)) != 0) 14415331Samw return (error); 14425331Samw 14435331Samw /* 14445331Samw * Prepend SMB_STREAM_PREFIX to stream name 14455331Samw */ 14465331Samw 14475331Samw solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 14485331Samw (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX, 14495331Samw stream_name); 14505331Samw 14515331Samw /* 14525331Samw * "name" will hold the on-disk name returned from smb_vop_lookup 14535331Samw * for the stream, including the SMB_STREAM_PREFIX. 14545331Samw */ 14555331Samw 14565331Samw name = kmem_zalloc(MAXNAMELEN, KM_SLEEP); 14575331Samw 14585331Samw if ((error = smb_vop_lookup(*xattrdirvpp, solaris_stream_name, vpp, 14595772Sas200622 name, flags, rootvp, cr)) != 0) { 14605331Samw VN_RELE(*xattrdirvpp); 14615331Samw } else { 14625331Samw (void) strlcpy(od_name, &(name[SMB_STREAM_PREFIX_LEN]), 14635331Samw MAXNAMELEN); 14645331Samw } 14655331Samw 14665331Samw kmem_free(solaris_stream_name, MAXNAMELEN); 14675331Samw kmem_free(name, MAXNAMELEN); 14685331Samw 14695331Samw return (error); 14705331Samw } 14715331Samw 14725331Samw int 14735331Samw smb_vop_stream_create(vnode_t *fvp, char *stream_name, smb_attr_t *attr, 14745772Sas200622 vnode_t **vpp, vnode_t **xattrdirvpp, int flags, cred_t *cr) 14755331Samw { 14765331Samw char *solaris_stream_name; 14775331Samw int error; 14785331Samw 14795331Samw if ((error = smb_vop_lookup_xattrdir(fvp, xattrdirvpp, 14805772Sas200622 LOOKUP_XATTR | CREATE_XATTR_DIR, cr)) != 0) 14815331Samw return (error); 14825331Samw 14835331Samw /* 14845331Samw * Prepend SMB_STREAM_PREFIX to stream name 14855331Samw */ 14865331Samw 14875331Samw solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 14885331Samw (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX, 14895331Samw stream_name); 14905331Samw 14915331Samw if ((error = smb_vop_create(*xattrdirvpp, solaris_stream_name, attr, 14925772Sas200622 vpp, flags, cr, NULL)) != 0) 14935331Samw VN_RELE(*xattrdirvpp); 14945331Samw 14955331Samw kmem_free(solaris_stream_name, MAXNAMELEN); 14965331Samw 14975331Samw return (error); 14985331Samw } 14995331Samw 15005331Samw int 15015772Sas200622 smb_vop_stream_remove(vnode_t *vp, char *stream_name, int flags, cred_t *cr) 15025331Samw { 15035331Samw char *solaris_stream_name; 15045331Samw vnode_t *xattrdirvp; 15055331Samw int error; 15065331Samw 15076139Sjb150015 error = smb_vop_lookup_xattrdir(vp, &xattrdirvp, LOOKUP_XATTR, cr); 15086139Sjb150015 if (error != 0) 15095331Samw return (error); 15105331Samw 15115331Samw /* 15125331Samw * Prepend SMB_STREAM_PREFIX to stream name 15135331Samw */ 15145331Samw 15155331Samw solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP); 15165331Samw (void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX, 15175331Samw stream_name); 15185331Samw 15195331Samw /* XXX might have to use kcred */ 15205772Sas200622 error = smb_vop_remove(xattrdirvp, solaris_stream_name, flags, cr); 15215331Samw 15225331Samw kmem_free(solaris_stream_name, MAXNAMELEN); 15235331Samw 15245331Samw return (error); 15255331Samw } 15265331Samw 15275331Samw /* 15285331Samw * smb_vop_stream_readdir() 15295331Samw * 15305331Samw * Note: stream_info.size is not filled in in this routine. 15315331Samw * It needs to be filled in by the caller due to the parameters for getattr. 15325331Samw * 15335331Samw * stream_info.name is set to the on-disk stream name with the SMB_STREAM_PREFIX 15345331Samw * removed. 15355331Samw */ 15365331Samw 15375331Samw int 15385331Samw smb_vop_stream_readdir(vnode_t *fvp, uint32_t *cookiep, 15395331Samw struct fs_stream_info *stream_info, vnode_t **vpp, vnode_t **xattrdirvpp, 15405772Sas200622 int flags, cred_t *cr) 15415331Samw { 15425331Samw int nsize = MAXNAMELEN-1; 15435331Samw int error = 0; 15445331Samw ino64_t ino; 15455331Samw char *tmp_name; 15465331Samw vnode_t *xattrdirvp; 15475331Samw vnode_t *vp; 15485331Samw 15495331Samw if ((error = smb_vop_lookup_xattrdir(fvp, &xattrdirvp, LOOKUP_XATTR, 15505772Sas200622 cr)) != 0) 15515331Samw return (error); 15525331Samw 15535331Samw bzero(stream_info->name, sizeof (stream_info->name)); 15545331Samw stream_info->size = 0; 15555331Samw 15565331Samw tmp_name = kmem_zalloc(MAXNAMELEN, KM_SLEEP); 15575331Samw 15585331Samw for (;;) { 15595331Samw error = smb_vop_readdir(xattrdirvp, cookiep, tmp_name, &nsize, 15605772Sas200622 &ino, &vp, NULL, flags | SMB_STREAM_RDDIR, cr); 15615331Samw 15625331Samw if (error || (*cookiep == SMB_EOF)) 15635331Samw break; 15645331Samw 15655331Samw if (strncmp(tmp_name, SMB_STREAM_PREFIX, 15665331Samw SMB_STREAM_PREFIX_LEN)) { 15675331Samw VN_RELE(vp); 15685331Samw continue; 15695331Samw } 15705331Samw 15715331Samw tmp_name[nsize] = '\0'; 15725331Samw (void) strlcpy(stream_info->name, 15735331Samw &(tmp_name[SMB_STREAM_PREFIX_LEN]), 15745331Samw sizeof (stream_info->name)); 15755331Samw 15765331Samw nsize -= SMB_STREAM_PREFIX_LEN; 15775331Samw break; 15785331Samw } 15795331Samw 15805331Samw if ((error == 0) && nsize) { 15815331Samw if (vpp) 15825331Samw *vpp = vp; 15835331Samw else 15845331Samw VN_RELE(vp); 15855331Samw 15865331Samw if (xattrdirvpp) 15875331Samw *xattrdirvpp = xattrdirvp; 15885331Samw else 15895331Samw VN_RELE(xattrdirvp); 15905331Samw 15915781Sjc198820 } else { 15925781Sjc198820 VN_RELE(xattrdirvp); 15935331Samw } 15945331Samw 15955331Samw kmem_free(tmp_name, MAXNAMELEN); 15965331Samw 15975331Samw return (error); 15985331Samw } 15995331Samw 16005331Samw int 16015331Samw smb_vop_lookup_xattrdir(vnode_t *fvp, vnode_t **xattrdirvpp, int flags, 16025772Sas200622 cred_t *cr) 16035331Samw { 16045331Samw int error; 16055331Samw 16065772Sas200622 error = VOP_LOOKUP(fvp, "", xattrdirvpp, NULL, flags, NULL, cr, 16075772Sas200622 &smb_ct, NULL, NULL); 16085331Samw return (error); 16095331Samw } 16105331Samw 16115331Samw /* 16125331Samw * smb_vop_traverse_check() 16135331Samw * 16145331Samw * This function checks to see if the passed-in vnode has a file system 16155331Samw * mounted on it. If it does, the mount point is "traversed" and the 16165331Samw * vnode for the root of the file system is returned. 16175331Samw */ 16185331Samw 16195331Samw int 16205331Samw smb_vop_traverse_check(vnode_t **vpp) 16215331Samw { 16225331Samw int error; 16235331Samw 16245331Samw if (vn_mountedvfs(*vpp) == 0) 16255331Samw return (0); 16265331Samw 16275331Samw /* 16285331Samw * traverse() may return a different held vnode, even in the error case. 16295331Samw * If it returns a different vnode, it will have released the original. 16305331Samw */ 16315331Samw 16325331Samw error = traverse(vpp); 16335331Samw 16345331Samw return (error); 16355331Samw } 16365331Samw 16375331Samw int /*ARGSUSED*/ 16385331Samw smb_vop_statfs(vnode_t *vp, struct statvfs64 *statp, cred_t *cr) 16395331Samw { 16405331Samw int error; 16415331Samw 16425331Samw error = VFS_STATVFS(vp->v_vfsp, statp); 16435331Samw 16445331Samw return (error); 16455331Samw } 16465331Samw 16475331Samw /* 16485331Samw * smb_vop_acl_read 16495331Samw * 16505331Samw * Reads the ACL of the specified file into 'aclp'. 16515331Samw * acl_type is the type of ACL which the filesystem supports. 16525331Samw * 16535331Samw * Caller has to free the allocated memory for aclp by calling 16545331Samw * acl_free(). 16555331Samw */ 16565331Samw int 16575331Samw smb_vop_acl_read(vnode_t *vp, acl_t **aclp, int flags, acl_type_t acl_type, 16585772Sas200622 cred_t *cr) 16595331Samw { 16605331Samw int error; 16615331Samw vsecattr_t vsecattr; 16625331Samw 16635331Samw ASSERT(vp); 16645331Samw ASSERT(aclp); 16655331Samw 16665331Samw *aclp = NULL; 16675331Samw bzero(&vsecattr, sizeof (vsecattr_t)); 16685331Samw 16695331Samw switch (acl_type) { 16705331Samw case ACLENT_T: 16715331Samw vsecattr.vsa_mask = VSA_ACL | VSA_ACLCNT | VSA_DFACL | 16725331Samw VSA_DFACLCNT; 16735331Samw break; 16745331Samw 16755331Samw case ACE_T: 16765331Samw vsecattr.vsa_mask = VSA_ACE | VSA_ACECNT | VSA_ACE_ACLFLAGS; 16775331Samw break; 16785331Samw 16795331Samw default: 16805331Samw return (EINVAL); 16815331Samw } 16825331Samw 16835772Sas200622 if (error = VOP_GETSECATTR(vp, &vsecattr, flags, cr, &smb_ct)) 16845331Samw return (error); 16855331Samw 16865521Sas200622 *aclp = smb_fsacl_from_vsa(&vsecattr, acl_type); 16875331Samw if (vp->v_type == VDIR) 16885331Samw (*aclp)->acl_flags |= ACL_IS_DIR; 16895331Samw 16905331Samw return (0); 16915331Samw } 16925331Samw 16935331Samw /* 16945331Samw * smb_vop_acl_write 16955331Samw * 16965331Samw * Writes the given ACL in aclp for the specified file. 16975331Samw */ 16985331Samw int 16995772Sas200622 smb_vop_acl_write(vnode_t *vp, acl_t *aclp, int flags, cred_t *cr) 17005331Samw { 17015331Samw int error; 17025331Samw vsecattr_t vsecattr; 17035331Samw int aclbsize; 17045331Samw 17055331Samw ASSERT(vp); 17065331Samw ASSERT(aclp); 17075331Samw 17085521Sas200622 error = smb_fsacl_to_vsa(aclp, &vsecattr, &aclbsize); 17095331Samw 17105331Samw if (error == 0) { 1711*6600Sas200622 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, &smb_ct); 17125772Sas200622 error = VOP_SETSECATTR(vp, &vsecattr, flags, cr, &smb_ct); 1713*6600Sas200622 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, &smb_ct); 17145331Samw } 17155331Samw 17165331Samw if (aclbsize && vsecattr.vsa_aclentp) 17175331Samw kmem_free(vsecattr.vsa_aclentp, aclbsize); 17185331Samw 17195331Samw return (error); 17205331Samw } 17215331Samw 17225331Samw /* 17235331Samw * smb_vop_acl_type 17245331Samw * 17255331Samw * Determines the ACL type for the given vnode. 17265331Samw * ACLENT_T is a Posix ACL and ACE_T is a ZFS ACL. 17275331Samw */ 17285331Samw acl_type_t 17295331Samw smb_vop_acl_type(vnode_t *vp) 17305331Samw { 17315331Samw int error; 17325331Samw ulong_t whichacl; 17335331Samw 17345331Samw error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &whichacl, kcred, NULL); 17355331Samw if (error != 0) { 17365331Samw /* 17375331Samw * If we got an error, then the filesystem 17385331Samw * likely does not understand the _PC_ACL_ENABLED 17395331Samw * pathconf. In this case, we fall back to trying 17405331Samw * POSIX-draft (aka UFS-style) ACLs. 17415331Samw */ 17425331Samw whichacl = _ACL_ACLENT_ENABLED; 17435331Samw } 17445331Samw 17455331Samw if (!(whichacl & (_ACL_ACE_ENABLED | _ACL_ACLENT_ENABLED))) { 17465331Samw /* 17475331Samw * If the file system supports neither ACE nor 17485331Samw * ACLENT ACLs we will fall back to UFS-style ACLs 17495331Samw * like we did above if there was an error upon 17505331Samw * calling VOP_PATHCONF. 17515331Samw * 17525331Samw * ACE and ACLENT type ACLs are the only interfaces 17535331Samw * supported thus far. If any other bits are set on 17545331Samw * 'whichacl' upon return from VOP_PATHCONF, we will 17555331Samw * ignore them. 17565331Samw */ 17575331Samw whichacl = _ACL_ACLENT_ENABLED; 17585331Samw } 17595331Samw 17605331Samw if (whichacl == _ACL_ACLENT_ENABLED) 17615331Samw return (ACLENT_T); 17625331Samw 17635331Samw return (ACE_T); 17645331Samw } 17655331Samw 17665331Samw static int zfs_perms[] = { 17675331Samw ACE_READ_DATA, ACE_WRITE_DATA, ACE_APPEND_DATA, ACE_READ_NAMED_ATTRS, 17685331Samw ACE_WRITE_NAMED_ATTRS, ACE_EXECUTE, ACE_DELETE_CHILD, 17695331Samw ACE_READ_ATTRIBUTES, ACE_WRITE_ATTRIBUTES, ACE_DELETE, ACE_READ_ACL, 17705331Samw ACE_WRITE_ACL, ACE_WRITE_OWNER, ACE_SYNCHRONIZE 17715331Samw }; 17725331Samw 17735331Samw static int unix_perms[] = { VREAD, VWRITE, VEXEC }; 17745331Samw /* 17755331Samw * smb_vop_eaccess 17765331Samw * 17775331Samw * Returns the effective permission of the given credential for the 17785331Samw * specified object. 17795331Samw * 17805331Samw * This is just a workaround. We need VFS/FS support for this. 17815331Samw */ 17825331Samw void 17835331Samw smb_vop_eaccess(vnode_t *vp, int *mode, int flags, vnode_t *dir_vp, cred_t *cr) 17845331Samw { 17855331Samw int error, i; 17865331Samw int pnum; 17875331Samw 17885331Samw *mode = 0; 17895331Samw 17905331Samw if (flags == V_ACE_MASK) { 17915331Samw pnum = sizeof (zfs_perms) / sizeof (int); 17925331Samw 17935331Samw for (i = 0; i < pnum; i++) { 17945331Samw error = smb_vop_access(vp, zfs_perms[i], flags, 17955331Samw dir_vp, cr); 17965331Samw if (error == 0) 17975331Samw *mode |= zfs_perms[i]; 17985331Samw } 17995331Samw } else { 18005331Samw pnum = sizeof (unix_perms) / sizeof (int); 18015331Samw 18025331Samw for (i = 0; i < pnum; i++) { 18035331Samw error = smb_vop_access(vp, unix_perms[i], flags, 18045331Samw dir_vp, cr); 18055331Samw if (error == 0) 18065331Samw *mode |= unix_perms[i]; 18075331Samw } 18085331Samw } 18095331Samw } 18105772Sas200622 18115772Sas200622 /* 18125772Sas200622 * smb_vop_shrlock() 18135772Sas200622 * 18145772Sas200622 * See comments for smb_fsop_shrlock() 18155772Sas200622 */ 18165772Sas200622 18175772Sas200622 int 18185772Sas200622 smb_vop_shrlock(vnode_t *vp, uint32_t uniq_fid, uint32_t desired_access, 18195772Sas200622 uint32_t share_access, cred_t *cr) 18205772Sas200622 { 18215772Sas200622 struct shrlock shr; 18225772Sas200622 struct shr_locowner shr_own; 18235772Sas200622 short new_access = 0; 18245772Sas200622 short deny = 0; 18255772Sas200622 int flag = 0; 18265772Sas200622 int cmd; 18275772Sas200622 18285772Sas200622 cmd = (nbl_need_check(vp)) ? F_SHARE_NBMAND : F_SHARE; 18295772Sas200622 18305772Sas200622 /* 18315772Sas200622 * Check if this is a metadata access 18325772Sas200622 */ 18335772Sas200622 18345772Sas200622 if ((desired_access & FILE_DATA_ALL) == 0) { 18355772Sas200622 new_access |= F_MDACC; 18365772Sas200622 } else { 18375772Sas200622 if (desired_access & (ACE_READ_DATA | ACE_EXECUTE)) { 18385772Sas200622 new_access |= F_RDACC; 18395772Sas200622 flag |= FREAD; 18405772Sas200622 } 18415772Sas200622 18425772Sas200622 if (desired_access & (ACE_WRITE_DATA | ACE_APPEND_DATA | 18435772Sas200622 ACE_ADD_FILE)) { 18445772Sas200622 new_access |= F_WRACC; 18455772Sas200622 flag |= FWRITE; 18465772Sas200622 } 18475772Sas200622 18485772Sas200622 if (SMB_DENY_READ(share_access)) { 18495772Sas200622 deny |= F_RDDNY; 18505772Sas200622 } 18515772Sas200622 18525772Sas200622 if (SMB_DENY_WRITE(share_access)) { 18535772Sas200622 deny |= F_WRDNY; 18545772Sas200622 } 18555772Sas200622 18565772Sas200622 if (cmd == F_SHARE_NBMAND) { 18575772Sas200622 if (desired_access & ACE_DELETE) 18585772Sas200622 new_access |= F_RMACC; 18595772Sas200622 18605772Sas200622 if (SMB_DENY_DELETE(share_access)) { 18615772Sas200622 deny |= F_RMDNY; 18625772Sas200622 } 18635772Sas200622 } 18645772Sas200622 } 18655772Sas200622 18665772Sas200622 shr.s_access = new_access; 18675772Sas200622 shr.s_deny = deny; 18685772Sas200622 shr.s_sysid = smb_ct.cc_sysid; 18695772Sas200622 shr.s_pid = uniq_fid; 18705772Sas200622 shr.s_own_len = sizeof (shr_own); 18715772Sas200622 shr.s_owner = (caddr_t)&shr_own; 18725772Sas200622 shr_own.sl_id = shr.s_sysid; 18735772Sas200622 shr_own.sl_pid = shr.s_pid; 18745772Sas200622 18755772Sas200622 return (VOP_SHRLOCK(vp, cmd, &shr, flag, cr, NULL)); 18765772Sas200622 } 18775772Sas200622 18785772Sas200622 int 18795772Sas200622 smb_vop_unshrlock(vnode_t *vp, uint32_t uniq_fid, cred_t *cr) 18805772Sas200622 { 18815772Sas200622 struct shrlock shr; 18825772Sas200622 struct shr_locowner shr_own; 18835772Sas200622 18845772Sas200622 /* 18855772Sas200622 * For s_access and s_deny, we do not need to pass in the original 18865772Sas200622 * values. 18875772Sas200622 */ 18885772Sas200622 18895772Sas200622 shr.s_access = 0; 18905772Sas200622 shr.s_deny = 0; 18915772Sas200622 shr.s_sysid = smb_ct.cc_sysid; 18925772Sas200622 shr.s_pid = uniq_fid; 18935772Sas200622 shr.s_own_len = sizeof (shr_own); 18945772Sas200622 shr.s_owner = (caddr_t)&shr_own; 18955772Sas200622 shr_own.sl_id = shr.s_sysid; 18965772Sas200622 shr_own.sl_pid = shr.s_pid; 18975772Sas200622 18985772Sas200622 return (VOP_SHRLOCK(vp, F_UNSHARE, &shr, 0, cr, NULL)); 18995772Sas200622 } 1900*6600Sas200622 1901*6600Sas200622 int 1902*6600Sas200622 smb_vop_frlock(vnode_t *vp, cred_t *cr, int flag, flock64_t *bf) 1903*6600Sas200622 { 1904*6600Sas200622 int cmd = nbl_need_check(vp) ? F_SETLK_NBMAND : F_SETLK; 1905*6600Sas200622 flk_callback_t flk_cb; 1906*6600Sas200622 1907*6600Sas200622 flk_init_callback(&flk_cb, smb_lock_frlock_callback, NULL); 1908*6600Sas200622 1909*6600Sas200622 return (VOP_FRLOCK(vp, cmd, bf, flag, 0, &flk_cb, cr, &smb_ct)); 1910*6600Sas200622 } 1911*6600Sas200622 1912*6600Sas200622 static callb_cpr_t * 1913*6600Sas200622 /* ARGSUSED */ 1914*6600Sas200622 smb_lock_frlock_callback(flk_cb_when_t when, void *error) 1915*6600Sas200622 { 1916*6600Sas200622 return (0); 1917*6600Sas200622 } 1918