14bff34e3Sthurlow /* 24bff34e3Sthurlow * Copyright (c) 2000-2001 Boris Popov 34bff34e3Sthurlow * All rights reserved. 44bff34e3Sthurlow * 54bff34e3Sthurlow * Redistribution and use in source and binary forms, with or without 64bff34e3Sthurlow * modification, are permitted provided that the following conditions 74bff34e3Sthurlow * are met: 84bff34e3Sthurlow * 1. Redistributions of source code must retain the above copyright 94bff34e3Sthurlow * notice, this list of conditions and the following disclaimer. 104bff34e3Sthurlow * 2. Redistributions in binary form must reproduce the above copyright 114bff34e3Sthurlow * notice, this list of conditions and the following disclaimer in the 124bff34e3Sthurlow * documentation and/or other materials provided with the distribution. 134bff34e3Sthurlow * 3. All advertising materials mentioning features or use of this software 144bff34e3Sthurlow * must display the following acknowledgement: 154bff34e3Sthurlow * This product includes software developed by Boris Popov. 164bff34e3Sthurlow * 4. Neither the name of the author nor the names of any co-contributors 174bff34e3Sthurlow * may be used to endorse or promote products derived from this software 184bff34e3Sthurlow * without specific prior written permission. 194bff34e3Sthurlow * 204bff34e3Sthurlow * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 214bff34e3Sthurlow * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 224bff34e3Sthurlow * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 234bff34e3Sthurlow * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 244bff34e3Sthurlow * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 254bff34e3Sthurlow * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 264bff34e3Sthurlow * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 274bff34e3Sthurlow * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 284bff34e3Sthurlow * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 294bff34e3Sthurlow * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 304bff34e3Sthurlow * SUCH DAMAGE. 314bff34e3Sthurlow * 324bff34e3Sthurlow * $Id: smbfs_vnops.c,v 1.128.36.1 2005/05/27 02:35:28 lindak Exp $ 334bff34e3Sthurlow */ 344bff34e3Sthurlow 354bff34e3Sthurlow /* 362f5e3e91SGordon Ross * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 374bff34e3Sthurlow * Use is subject to license terms. 384bff34e3Sthurlow */ 394bff34e3Sthurlow 404bff34e3Sthurlow #include <sys/systm.h> 414bff34e3Sthurlow #include <sys/cred.h> 424bff34e3Sthurlow #include <sys/vnode.h> 434bff34e3Sthurlow #include <sys/vfs.h> 447568150aSgwr #include <sys/filio.h> 454bff34e3Sthurlow #include <sys/uio.h> 464bff34e3Sthurlow #include <sys/dirent.h> 474bff34e3Sthurlow #include <sys/errno.h> 48613a2f6bSGordon Ross #include <sys/sunddi.h> 494bff34e3Sthurlow #include <sys/sysmacros.h> 504bff34e3Sthurlow #include <sys/kmem.h> 514bff34e3Sthurlow #include <sys/cmn_err.h> 524bff34e3Sthurlow #include <sys/vfs_opreg.h> 534bff34e3Sthurlow #include <sys/policy.h> 544bff34e3Sthurlow 554bff34e3Sthurlow #include <netsmb/smb_osdep.h> 564bff34e3Sthurlow #include <netsmb/smb.h> 574bff34e3Sthurlow #include <netsmb/smb_conn.h> 584bff34e3Sthurlow #include <netsmb/smb_subr.h> 594bff34e3Sthurlow 604bff34e3Sthurlow #include <smbfs/smbfs.h> 614bff34e3Sthurlow #include <smbfs/smbfs_node.h> 624bff34e3Sthurlow #include <smbfs/smbfs_subr.h> 634bff34e3Sthurlow 647568150aSgwr #include <sys/fs/smbfs_ioctl.h> 654bff34e3Sthurlow #include <fs/fs_subr.h> 664bff34e3Sthurlow 675ecede33SGordon Ross /* 685ecede33SGordon Ross * We assign directory offsets like the NFS client, where the 695ecede33SGordon Ross * offset increments by _one_ after each directory entry. 705ecede33SGordon Ross * Further, the entries "." and ".." are always at offsets 715ecede33SGordon Ross * zero and one (respectively) and the "real" entries from 725ecede33SGordon Ross * the server appear at offsets starting with two. This 735ecede33SGordon Ross * macro is used to initialize the n_dirofs field after 745ecede33SGordon Ross * setting n_dirseq with a _findopen call. 755ecede33SGordon Ross */ 765ecede33SGordon Ross #define FIRST_DIROFS 2 775ecede33SGordon Ross 784bff34e3Sthurlow /* 794bff34e3Sthurlow * These characters are illegal in NTFS file names. 804bff34e3Sthurlow * ref: http://support.microsoft.com/kb/147438 8191d632c8Sgwr * 8291d632c8Sgwr * Careful! The check in the XATTR case skips the 8391d632c8Sgwr * first character to allow colon in XATTR names. 844bff34e3Sthurlow */ 854bff34e3Sthurlow static const char illegal_chars[] = { 8691d632c8Sgwr ':', /* colon - keep this first! */ 874bff34e3Sthurlow '\\', /* back slash */ 884bff34e3Sthurlow '/', /* slash */ 894bff34e3Sthurlow '*', /* asterisk */ 904bff34e3Sthurlow '?', /* question mark */ 914bff34e3Sthurlow '"', /* double quote */ 924bff34e3Sthurlow '<', /* less than sign */ 934bff34e3Sthurlow '>', /* greater than sign */ 944bff34e3Sthurlow '|', /* vertical bar */ 954bff34e3Sthurlow 0 964bff34e3Sthurlow }; 974bff34e3Sthurlow 984bff34e3Sthurlow /* 994bff34e3Sthurlow * Turning this on causes nodes to be created in the cache 100*02d09e03SGordon Ross * during directory listings, normally avoiding a second 101*02d09e03SGordon Ross * OtW attribute fetch just after a readdir. 1024bff34e3Sthurlow */ 103*02d09e03SGordon Ross int smbfs_fastlookup = 1; 1044bff34e3Sthurlow 1054bff34e3Sthurlow /* local static function defines */ 1064bff34e3Sthurlow 107*02d09e03SGordon Ross static int smbfslookup_cache(vnode_t *, char *, int, vnode_t **, 108*02d09e03SGordon Ross cred_t *); 1094bff34e3Sthurlow static int smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, 110*02d09e03SGordon Ross int cache_ok, caller_context_t *); 1114bff34e3Sthurlow static int smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, 1124bff34e3Sthurlow cred_t *cr, caller_context_t *); 1134bff34e3Sthurlow static int smbfssetattr(vnode_t *, struct vattr *, int, cred_t *); 1144bff34e3Sthurlow static int smbfs_accessx(void *, int, cred_t *); 1154bff34e3Sthurlow static int smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp, 1164bff34e3Sthurlow caller_context_t *); 1174bff34e3Sthurlow /* 1184bff34e3Sthurlow * These are the vnode ops routines which implement the vnode interface to 1194bff34e3Sthurlow * the networked file system. These routines just take their parameters, 1204bff34e3Sthurlow * make them look networkish by putting the right info into interface structs, 1214bff34e3Sthurlow * and then calling the appropriate remote routine(s) to do the work. 1224bff34e3Sthurlow * 1234bff34e3Sthurlow * Note on directory name lookup cacheing: If we detect a stale fhandle, 1244bff34e3Sthurlow * we purge the directory cache relative to that vnode. This way, the 1254bff34e3Sthurlow * user won't get burned by the cache repeatedly. See <smbfs/smbnode.h> for 1264bff34e3Sthurlow * more details on smbnode locking. 1274bff34e3Sthurlow */ 1284bff34e3Sthurlow 1294bff34e3Sthurlow static int smbfs_open(vnode_t **, int, cred_t *, caller_context_t *); 1304bff34e3Sthurlow static int smbfs_close(vnode_t *, int, int, offset_t, cred_t *, 1314bff34e3Sthurlow caller_context_t *); 1324bff34e3Sthurlow static int smbfs_read(vnode_t *, struct uio *, int, cred_t *, 1334bff34e3Sthurlow caller_context_t *); 1344bff34e3Sthurlow static int smbfs_write(vnode_t *, struct uio *, int, cred_t *, 1354bff34e3Sthurlow caller_context_t *); 1367568150aSgwr static int smbfs_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *, 1377568150aSgwr caller_context_t *); 1384bff34e3Sthurlow static int smbfs_getattr(vnode_t *, struct vattr *, int, cred_t *, 1394bff34e3Sthurlow caller_context_t *); 1404bff34e3Sthurlow static int smbfs_setattr(vnode_t *, struct vattr *, int, cred_t *, 1414bff34e3Sthurlow caller_context_t *); 1424bff34e3Sthurlow static int smbfs_access(vnode_t *, int, int, cred_t *, caller_context_t *); 1434bff34e3Sthurlow static int smbfs_fsync(vnode_t *, int, cred_t *, caller_context_t *); 1444bff34e3Sthurlow static void smbfs_inactive(vnode_t *, cred_t *, caller_context_t *); 1454bff34e3Sthurlow static int smbfs_lookup(vnode_t *, char *, vnode_t **, struct pathname *, 1464bff34e3Sthurlow int, vnode_t *, cred_t *, caller_context_t *, 1474bff34e3Sthurlow int *, pathname_t *); 1484bff34e3Sthurlow static int smbfs_create(vnode_t *, char *, struct vattr *, enum vcexcl, 1494bff34e3Sthurlow int, vnode_t **, cred_t *, int, caller_context_t *, 1504bff34e3Sthurlow vsecattr_t *); 1514bff34e3Sthurlow static int smbfs_remove(vnode_t *, char *, cred_t *, caller_context_t *, 1524bff34e3Sthurlow int); 1534bff34e3Sthurlow static int smbfs_rename(vnode_t *, char *, vnode_t *, char *, cred_t *, 1544bff34e3Sthurlow caller_context_t *, int); 1554bff34e3Sthurlow static int smbfs_mkdir(vnode_t *, char *, struct vattr *, vnode_t **, 1564bff34e3Sthurlow cred_t *, caller_context_t *, int, vsecattr_t *); 1574bff34e3Sthurlow static int smbfs_rmdir(vnode_t *, char *, vnode_t *, cred_t *, 1584bff34e3Sthurlow caller_context_t *, int); 1594bff34e3Sthurlow static int smbfs_readdir(vnode_t *, struct uio *, cred_t *, int *, 1604bff34e3Sthurlow caller_context_t *, int); 1614bff34e3Sthurlow static int smbfs_rwlock(vnode_t *, int, caller_context_t *); 1624bff34e3Sthurlow static void smbfs_rwunlock(vnode_t *, int, caller_context_t *); 1634bff34e3Sthurlow static int smbfs_seek(vnode_t *, offset_t, offset_t *, caller_context_t *); 1644bff34e3Sthurlow static int smbfs_frlock(vnode_t *, int, struct flock64 *, int, offset_t, 1654bff34e3Sthurlow struct flk_callback *, cred_t *, caller_context_t *); 1664bff34e3Sthurlow static int smbfs_space(vnode_t *, int, struct flock64 *, int, offset_t, 1674bff34e3Sthurlow cred_t *, caller_context_t *); 1684bff34e3Sthurlow static int smbfs_pathconf(vnode_t *, int, ulong_t *, cred_t *, 1694bff34e3Sthurlow caller_context_t *); 1707568150aSgwr static int smbfs_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *, 1717568150aSgwr caller_context_t *); 1727568150aSgwr static int smbfs_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *, 1737568150aSgwr caller_context_t *); 1744bff34e3Sthurlow static int smbfs_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *, 1754bff34e3Sthurlow caller_context_t *); 1764bff34e3Sthurlow 1774bff34e3Sthurlow /* Dummy function to use until correct function is ported in */ 1784bff34e3Sthurlow int noop_vnodeop() { 1794bff34e3Sthurlow return (0); 1804bff34e3Sthurlow } 1814bff34e3Sthurlow 1824bff34e3Sthurlow struct vnodeops *smbfs_vnodeops = NULL; 1834bff34e3Sthurlow 1844bff34e3Sthurlow /* 1854bff34e3Sthurlow * Most unimplemented ops will return ENOSYS because of fs_nosys(). 1864bff34e3Sthurlow * The only ops where that won't work are ACCESS (due to open(2) 1877568150aSgwr * failures) and ... (anything else left?) 1884bff34e3Sthurlow */ 1894bff34e3Sthurlow const fs_operation_def_t smbfs_vnodeops_template[] = { 1907568150aSgwr { VOPNAME_OPEN, { .vop_open = smbfs_open } }, 1917568150aSgwr { VOPNAME_CLOSE, { .vop_close = smbfs_close } }, 1927568150aSgwr { VOPNAME_READ, { .vop_read = smbfs_read } }, 1937568150aSgwr { VOPNAME_WRITE, { .vop_write = smbfs_write } }, 1947568150aSgwr { VOPNAME_IOCTL, { .vop_ioctl = smbfs_ioctl } }, 1957568150aSgwr { VOPNAME_GETATTR, { .vop_getattr = smbfs_getattr } }, 1967568150aSgwr { VOPNAME_SETATTR, { .vop_setattr = smbfs_setattr } }, 1977568150aSgwr { VOPNAME_ACCESS, { .vop_access = smbfs_access } }, 1987568150aSgwr { VOPNAME_LOOKUP, { .vop_lookup = smbfs_lookup } }, 1997568150aSgwr { VOPNAME_CREATE, { .vop_create = smbfs_create } }, 2007568150aSgwr { VOPNAME_REMOVE, { .vop_remove = smbfs_remove } }, 2017568150aSgwr { VOPNAME_LINK, { .error = fs_nosys } }, /* smbfs_link, */ 2027568150aSgwr { VOPNAME_RENAME, { .vop_rename = smbfs_rename } }, 2037568150aSgwr { VOPNAME_MKDIR, { .vop_mkdir = smbfs_mkdir } }, 2047568150aSgwr { VOPNAME_RMDIR, { .vop_rmdir = smbfs_rmdir } }, 2057568150aSgwr { VOPNAME_READDIR, { .vop_readdir = smbfs_readdir } }, 2067568150aSgwr { VOPNAME_SYMLINK, { .error = fs_nosys } }, /* smbfs_symlink, */ 2077568150aSgwr { VOPNAME_READLINK, { .error = fs_nosys } }, /* smbfs_readlink, */ 2087568150aSgwr { VOPNAME_FSYNC, { .vop_fsync = smbfs_fsync } }, 2097568150aSgwr { VOPNAME_INACTIVE, { .vop_inactive = smbfs_inactive } }, 2107568150aSgwr { VOPNAME_FID, { .error = fs_nosys } }, /* smbfs_fid, */ 2117568150aSgwr { VOPNAME_RWLOCK, { .vop_rwlock = smbfs_rwlock } }, 2127568150aSgwr { VOPNAME_RWUNLOCK, { .vop_rwunlock = smbfs_rwunlock } }, 2137568150aSgwr { VOPNAME_SEEK, { .vop_seek = smbfs_seek } }, 2147568150aSgwr { VOPNAME_FRLOCK, { .vop_frlock = smbfs_frlock } }, 2157568150aSgwr { VOPNAME_SPACE, { .vop_space = smbfs_space } }, 2167568150aSgwr { VOPNAME_REALVP, { .error = fs_nosys } }, /* smbfs_realvp, */ 2177568150aSgwr { VOPNAME_GETPAGE, { .error = fs_nosys } }, /* smbfs_getpage, */ 2187568150aSgwr { VOPNAME_PUTPAGE, { .error = fs_nosys } }, /* smbfs_putpage, */ 2197568150aSgwr { VOPNAME_MAP, { .error = fs_nosys } }, /* smbfs_map, */ 2207568150aSgwr { VOPNAME_ADDMAP, { .error = fs_nosys } }, /* smbfs_addmap, */ 2217568150aSgwr { VOPNAME_DELMAP, { .error = fs_nosys } }, /* smbfs_delmap, */ 2227568150aSgwr { VOPNAME_DUMP, { .error = fs_nosys } }, /* smbfs_dump, */ 2237568150aSgwr { VOPNAME_PATHCONF, { .vop_pathconf = smbfs_pathconf } }, 2247568150aSgwr { VOPNAME_PAGEIO, { .error = fs_nosys } }, /* smbfs_pageio, */ 2257568150aSgwr { VOPNAME_SETSECATTR, { .vop_setsecattr = smbfs_setsecattr } }, 2267568150aSgwr { VOPNAME_GETSECATTR, { .vop_getsecattr = smbfs_getsecattr } }, 2277568150aSgwr { VOPNAME_SHRLOCK, { .vop_shrlock = smbfs_shrlock } }, 2284bff34e3Sthurlow { NULL, NULL } 2294bff34e3Sthurlow }; 2304bff34e3Sthurlow 2314bff34e3Sthurlow /* 2324bff34e3Sthurlow * XXX 2334bff34e3Sthurlow * When new and relevant functionality is enabled, we should be 2344bff34e3Sthurlow * calling vfs_set_feature() to inform callers that pieces of 2359660e5cbSJanice Chang * functionality are available, per PSARC 2007/227. 2364bff34e3Sthurlow */ 2374bff34e3Sthurlow /* ARGSUSED */ 2384bff34e3Sthurlow static int 2394bff34e3Sthurlow smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct) 2404bff34e3Sthurlow { 2414bff34e3Sthurlow smbnode_t *np; 2424bff34e3Sthurlow vnode_t *vp; 243*02d09e03SGordon Ross smbfattr_t fa; 2444bff34e3Sthurlow u_int32_t rights, rightsrcvd; 2454bff34e3Sthurlow u_int16_t fid, oldfid; 246613a2f6bSGordon Ross int oldgenid; 2474bff34e3Sthurlow struct smb_cred scred; 2484bff34e3Sthurlow smbmntinfo_t *smi; 249613a2f6bSGordon Ross smb_share_t *ssp; 2504bff34e3Sthurlow cred_t *oldcr; 2514bff34e3Sthurlow int tmperror; 2524bff34e3Sthurlow int error = 0; 2534bff34e3Sthurlow 2544bff34e3Sthurlow vp = *vpp; 2554bff34e3Sthurlow np = VTOSMB(vp); 2564bff34e3Sthurlow smi = VTOSMI(vp); 257613a2f6bSGordon Ross ssp = smi->smi_share; 2584bff34e3Sthurlow 2594bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 2604bff34e3Sthurlow return (EIO); 2614bff34e3Sthurlow 2624bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 2634bff34e3Sthurlow return (EIO); 2644bff34e3Sthurlow 2654bff34e3Sthurlow if (vp->v_type != VREG && vp->v_type != VDIR) { /* XXX VLNK? */ 2664bff34e3Sthurlow SMBVDEBUG("open eacces vtype=%d\n", vp->v_type); 2674bff34e3Sthurlow return (EACCES); 2684bff34e3Sthurlow } 2694bff34e3Sthurlow 2704bff34e3Sthurlow /* 2714bff34e3Sthurlow * Get exclusive access to n_fid and related stuff. 2724bff34e3Sthurlow * No returns after this until out. 2734bff34e3Sthurlow */ 2744bff34e3Sthurlow if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp))) 2754bff34e3Sthurlow return (EINTR); 276613a2f6bSGordon Ross smb_credinit(&scred, cr); 2774bff34e3Sthurlow 27891d632c8Sgwr /* 27991d632c8Sgwr * Keep track of the vnode type at first open. 28091d632c8Sgwr * It may change later, and we need close to do 28191d632c8Sgwr * cleanup for the type we opened. Also deny 28291d632c8Sgwr * open of new types until old type is closed. 28391d632c8Sgwr * XXX: Per-open instance nodes whould help. 28491d632c8Sgwr */ 28591d632c8Sgwr if (np->n_ovtype == VNON) { 28691d632c8Sgwr ASSERT(np->n_dirrefs == 0); 28791d632c8Sgwr ASSERT(np->n_fidrefs == 0); 28891d632c8Sgwr } else if (np->n_ovtype != vp->v_type) { 28991d632c8Sgwr SMBVDEBUG("open n_ovtype=%d v_type=%d\n", 29091d632c8Sgwr np->n_ovtype, vp->v_type); 29191d632c8Sgwr error = EACCES; 29291d632c8Sgwr goto out; 29391d632c8Sgwr } 29491d632c8Sgwr 2954bff34e3Sthurlow /* 2965ecede33SGordon Ross * Directory open. See smbfs_readvdir() 2974bff34e3Sthurlow */ 2984bff34e3Sthurlow if (vp->v_type == VDIR) { 2995ecede33SGordon Ross if (np->n_dirseq == NULL) { 3005ecede33SGordon Ross /* first open */ 3015ecede33SGordon Ross error = smbfs_smb_findopen(np, "*", 1, 3025ecede33SGordon Ross SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, 3035ecede33SGordon Ross &scred, &np->n_dirseq); 3045ecede33SGordon Ross if (error != 0) 3055ecede33SGordon Ross goto out; 3065ecede33SGordon Ross } 3075ecede33SGordon Ross np->n_dirofs = FIRST_DIROFS; 3084bff34e3Sthurlow np->n_dirrefs++; 3094bff34e3Sthurlow goto have_fid; 3104bff34e3Sthurlow } 3114bff34e3Sthurlow 3124bff34e3Sthurlow /* 3134bff34e3Sthurlow * If caller specified O_TRUNC/FTRUNC, then be sure to set 3144bff34e3Sthurlow * FWRITE (to drive successful setattr(size=0) after open) 3154bff34e3Sthurlow */ 3164bff34e3Sthurlow if (flag & FTRUNC) 3174bff34e3Sthurlow flag |= FWRITE; 3184bff34e3Sthurlow 3194bff34e3Sthurlow /* 320613a2f6bSGordon Ross * If we already have it open, and the FID is still valid, 321613a2f6bSGordon Ross * check whether the rights are sufficient for FID reuse. 3224bff34e3Sthurlow */ 323613a2f6bSGordon Ross if (np->n_fidrefs > 0 && 324613a2f6bSGordon Ross np->n_vcgenid == ssp->ss_vcgenid) { 3254bff34e3Sthurlow int upgrade = 0; 3264bff34e3Sthurlow 3274bff34e3Sthurlow if ((flag & FWRITE) && 328*02d09e03SGordon Ross !(np->n_rights & SA_RIGHT_FILE_WRITE_DATA)) 3294bff34e3Sthurlow upgrade = 1; 3304bff34e3Sthurlow if ((flag & FREAD) && 331*02d09e03SGordon Ross !(np->n_rights & SA_RIGHT_FILE_READ_DATA)) 3324bff34e3Sthurlow upgrade = 1; 3334bff34e3Sthurlow if (!upgrade) { 3344bff34e3Sthurlow /* 3354bff34e3Sthurlow * the existing open is good enough 3364bff34e3Sthurlow */ 3374bff34e3Sthurlow np->n_fidrefs++; 3384bff34e3Sthurlow goto have_fid; 3394bff34e3Sthurlow } 3404bff34e3Sthurlow } 3414bff34e3Sthurlow rights = np->n_fidrefs ? np->n_rights : 0; 3424bff34e3Sthurlow 3434bff34e3Sthurlow /* 3444bff34e3Sthurlow * we always ask for READ_CONTROL so we can always get the 34591d632c8Sgwr * owner/group IDs to satisfy a stat. Ditto attributes. 3464bff34e3Sthurlow */ 34791d632c8Sgwr rights |= (STD_RIGHT_READ_CONTROL_ACCESS | 34891d632c8Sgwr SA_RIGHT_FILE_READ_ATTRIBUTES); 3494bff34e3Sthurlow if ((flag & FREAD)) 3504bff34e3Sthurlow rights |= SA_RIGHT_FILE_READ_DATA; 3514bff34e3Sthurlow if ((flag & FWRITE)) 352*02d09e03SGordon Ross rights |= SA_RIGHT_FILE_WRITE_DATA | 353*02d09e03SGordon Ross SA_RIGHT_FILE_APPEND_DATA | 354*02d09e03SGordon Ross SA_RIGHT_FILE_WRITE_ATTRIBUTES; 355*02d09e03SGordon Ross 356*02d09e03SGordon Ross bzero(&fa, sizeof (fa)); 357*02d09e03SGordon Ross error = smbfs_smb_open(np, 358*02d09e03SGordon Ross NULL, 0, 0, /* name nmlen xattr */ 359*02d09e03SGordon Ross rights, &scred, 360*02d09e03SGordon Ross &fid, &rightsrcvd, &fa); 3614bff34e3Sthurlow if (error) 3624bff34e3Sthurlow goto out; 363*02d09e03SGordon Ross smbfs_attrcache_fa(vp, &fa); 3644bff34e3Sthurlow 3654bff34e3Sthurlow /* 3664bff34e3Sthurlow * We have a new FID and access rights. 3674bff34e3Sthurlow */ 3684bff34e3Sthurlow oldfid = np->n_fid; 369613a2f6bSGordon Ross oldgenid = np->n_vcgenid; 3704bff34e3Sthurlow np->n_fid = fid; 371613a2f6bSGordon Ross np->n_vcgenid = ssp->ss_vcgenid; 3724bff34e3Sthurlow np->n_rights = rightsrcvd; 3734bff34e3Sthurlow np->n_fidrefs++; 374613a2f6bSGordon Ross if (np->n_fidrefs > 1 && 375613a2f6bSGordon Ross oldgenid == ssp->ss_vcgenid) { 3764bff34e3Sthurlow /* 3774bff34e3Sthurlow * We already had it open (presumably because 3784bff34e3Sthurlow * it was open with insufficient rights.) 3794bff34e3Sthurlow * Close old wire-open. 3804bff34e3Sthurlow */ 381613a2f6bSGordon Ross tmperror = smbfs_smb_close(ssp, 382*02d09e03SGordon Ross oldfid, NULL, &scred); 3834bff34e3Sthurlow if (tmperror) 3844bff34e3Sthurlow SMBVDEBUG("error %d closing %s\n", 3854bff34e3Sthurlow tmperror, np->n_rpath); 3864bff34e3Sthurlow } 3874bff34e3Sthurlow 3884bff34e3Sthurlow /* 3894bff34e3Sthurlow * This thread did the open. 3904bff34e3Sthurlow * Save our credentials too. 3914bff34e3Sthurlow */ 3924bff34e3Sthurlow mutex_enter(&np->r_statelock); 3934bff34e3Sthurlow oldcr = np->r_cred; 3944bff34e3Sthurlow np->r_cred = cr; 3954bff34e3Sthurlow crhold(cr); 3964bff34e3Sthurlow if (oldcr) 3974bff34e3Sthurlow crfree(oldcr); 3984bff34e3Sthurlow mutex_exit(&np->r_statelock); 3994bff34e3Sthurlow 4004bff34e3Sthurlow have_fid: 40191d632c8Sgwr /* 40291d632c8Sgwr * Keep track of the vnode type at first open. 40391d632c8Sgwr * (see comments above) 40491d632c8Sgwr */ 40591d632c8Sgwr if (np->n_ovtype == VNON) 40691d632c8Sgwr np->n_ovtype = vp->v_type; 4074bff34e3Sthurlow 4084bff34e3Sthurlow out: 4094bff34e3Sthurlow smb_credrele(&scred); 4104bff34e3Sthurlow smbfs_rw_exit(&np->r_lkserlock); 4114bff34e3Sthurlow return (error); 4124bff34e3Sthurlow } 4134bff34e3Sthurlow 4144bff34e3Sthurlow /*ARGSUSED*/ 4154bff34e3Sthurlow static int 4164bff34e3Sthurlow smbfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr, 4174bff34e3Sthurlow caller_context_t *ct) 4184bff34e3Sthurlow { 4194bff34e3Sthurlow smbnode_t *np; 420613a2f6bSGordon Ross smbmntinfo_t *smi; 421613a2f6bSGordon Ross smb_share_t *ssp; 422*02d09e03SGordon Ross cred_t *oldcr; 4234bff34e3Sthurlow int error = 0; 4244bff34e3Sthurlow struct smb_cred scred; 4254bff34e3Sthurlow 4264bff34e3Sthurlow np = VTOSMB(vp); 427613a2f6bSGordon Ross smi = VTOSMI(vp); 428613a2f6bSGordon Ross ssp = smi->smi_share; 4294bff34e3Sthurlow 4304bff34e3Sthurlow /* 4314bff34e3Sthurlow * Don't "bail out" for VFS_UNMOUNTED here, 4324bff34e3Sthurlow * as we want to do cleanup, etc. 4334bff34e3Sthurlow */ 4344bff34e3Sthurlow 4354bff34e3Sthurlow /* 4364bff34e3Sthurlow * zone_enter(2) prevents processes from changing zones with SMBFS files 4374bff34e3Sthurlow * open; if we happen to get here from the wrong zone we can't do 4384bff34e3Sthurlow * anything over the wire. 4394bff34e3Sthurlow */ 4404bff34e3Sthurlow if (VTOSMI(vp)->smi_zone != curproc->p_zone) { 4414bff34e3Sthurlow /* 4424bff34e3Sthurlow * We could attempt to clean up locks, except we're sure 4434bff34e3Sthurlow * that the current process didn't acquire any locks on 4444bff34e3Sthurlow * the file: any attempt to lock a file belong to another zone 4454bff34e3Sthurlow * will fail, and one can't lock an SMBFS file and then change 4464bff34e3Sthurlow * zones, as that fails too. 4474bff34e3Sthurlow * 4484bff34e3Sthurlow * Returning an error here is the sane thing to do. A 4494bff34e3Sthurlow * subsequent call to VN_RELE() which translates to a 4504bff34e3Sthurlow * smbfs_inactive() will clean up state: if the zone of the 4514bff34e3Sthurlow * vnode's origin is still alive and kicking, an async worker 4524bff34e3Sthurlow * thread will handle the request (from the correct zone), and 4534bff34e3Sthurlow * everything (minus the final smbfs_getattr_otw() call) should 4544bff34e3Sthurlow * be OK. If the zone is going away smbfs_async_inactive() will 4554bff34e3Sthurlow * throw away cached pages inline. 4564bff34e3Sthurlow */ 4574bff34e3Sthurlow return (EIO); 4584bff34e3Sthurlow } 4594bff34e3Sthurlow 4604bff34e3Sthurlow /* 4614bff34e3Sthurlow * If we are using local locking for this filesystem, then 4624bff34e3Sthurlow * release all of the SYSV style record locks. Otherwise, 4634bff34e3Sthurlow * we are doing network locking and we need to release all 4644bff34e3Sthurlow * of the network locks. All of the locks held by this 4654bff34e3Sthurlow * process on this file are released no matter what the 4664bff34e3Sthurlow * incoming reference count is. 4674bff34e3Sthurlow */ 4684bff34e3Sthurlow if (VTOSMI(vp)->smi_flags & SMI_LLOCK) { 469613a2f6bSGordon Ross pid_t pid = ddi_get_pid(); 470613a2f6bSGordon Ross cleanlocks(vp, pid, 0); 471613a2f6bSGordon Ross cleanshares(vp, pid); 4724bff34e3Sthurlow } 4734bff34e3Sthurlow 4744bff34e3Sthurlow /* 475*02d09e03SGordon Ross * This (passed in) count is the ref. count from the 476*02d09e03SGordon Ross * user's file_t before the closef call (fio.c). 477*02d09e03SGordon Ross * We only care when the reference goes away. 4784bff34e3Sthurlow */ 479*02d09e03SGordon Ross if (count > 1) 480*02d09e03SGordon Ross return (0); 4814bff34e3Sthurlow 4824bff34e3Sthurlow /* 4834bff34e3Sthurlow * Do the CIFS close. 4844bff34e3Sthurlow * Darwin code 4854bff34e3Sthurlow */ 4864bff34e3Sthurlow 4874bff34e3Sthurlow /* 4884bff34e3Sthurlow * Exclusive lock for modifying n_fid stuff. 4894bff34e3Sthurlow * Don't want this one ever interruptible. 4904bff34e3Sthurlow */ 4914bff34e3Sthurlow (void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0); 492613a2f6bSGordon Ross smb_credinit(&scred, cr); 4934bff34e3Sthurlow 4944bff34e3Sthurlow error = 0; 49591d632c8Sgwr 49691d632c8Sgwr /* 49791d632c8Sgwr * Note that vp->v_type may change if a remote node 49891d632c8Sgwr * is deleted and recreated as a different type, and 49991d632c8Sgwr * our getattr may change v_type accordingly. 50091d632c8Sgwr * Now use n_ovtype to keep track of the v_type 50191d632c8Sgwr * we had during open (see comments above). 50291d632c8Sgwr */ 50391d632c8Sgwr if (np->n_ovtype == VDIR) { 5044bff34e3Sthurlow struct smbfs_fctx *fctx; 5054bff34e3Sthurlow ASSERT(np->n_dirrefs > 0); 5064bff34e3Sthurlow if (--np->n_dirrefs) 5074bff34e3Sthurlow goto out; 5084bff34e3Sthurlow if ((fctx = np->n_dirseq) != NULL) { 5094bff34e3Sthurlow np->n_dirseq = NULL; 5105ecede33SGordon Ross np->n_dirofs = 0; 5114bff34e3Sthurlow error = smbfs_smb_findclose(fctx, &scred); 5124bff34e3Sthurlow } 5134bff34e3Sthurlow } else { 5144bff34e3Sthurlow uint16_t ofid; 5154bff34e3Sthurlow ASSERT(np->n_fidrefs > 0); 5164bff34e3Sthurlow if (--np->n_fidrefs) 5174bff34e3Sthurlow goto out; 5184bff34e3Sthurlow if ((ofid = np->n_fid) != SMB_FID_UNUSED) { 5194bff34e3Sthurlow np->n_fid = SMB_FID_UNUSED; 520613a2f6bSGordon Ross /* After reconnect, n_fid is invalid */ 521613a2f6bSGordon Ross if (np->n_vcgenid == ssp->ss_vcgenid) { 522613a2f6bSGordon Ross error = smbfs_smb_close( 523613a2f6bSGordon Ross ssp, ofid, NULL, &scred); 524613a2f6bSGordon Ross } 5254bff34e3Sthurlow } 5264bff34e3Sthurlow } 5274bff34e3Sthurlow if (error) { 528*02d09e03SGordon Ross SMBVDEBUG("error %d closing %s\n", 5294bff34e3Sthurlow error, np->n_rpath); 5304bff34e3Sthurlow } 5314bff34e3Sthurlow 53291d632c8Sgwr /* Allow next open to use any v_type. */ 53391d632c8Sgwr np->n_ovtype = VNON; 53491d632c8Sgwr 535*02d09e03SGordon Ross /* 536*02d09e03SGordon Ross * Other "last close" stuff. 537*02d09e03SGordon Ross */ 538*02d09e03SGordon Ross mutex_enter(&np->r_statelock); 5394bff34e3Sthurlow if (np->n_flag & NATTRCHANGED) 540*02d09e03SGordon Ross smbfs_attrcache_rm_locked(np); 541*02d09e03SGordon Ross oldcr = np->r_cred; 542*02d09e03SGordon Ross np->r_cred = NULL; 543*02d09e03SGordon Ross mutex_exit(&np->r_statelock); 544*02d09e03SGordon Ross if (oldcr != NULL) 545*02d09e03SGordon Ross crfree(oldcr); 5464bff34e3Sthurlow 5474bff34e3Sthurlow out: 5484bff34e3Sthurlow smb_credrele(&scred); 5494bff34e3Sthurlow smbfs_rw_exit(&np->r_lkserlock); 5504bff34e3Sthurlow 5514bff34e3Sthurlow /* don't return any errors */ 5524bff34e3Sthurlow return (0); 5534bff34e3Sthurlow } 5544bff34e3Sthurlow 5554bff34e3Sthurlow /* ARGSUSED */ 5564bff34e3Sthurlow static int 5574bff34e3Sthurlow smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr, 5584bff34e3Sthurlow caller_context_t *ct) 5594bff34e3Sthurlow { 5609c9af259SGordon Ross struct smb_cred scred; 5619c9af259SGordon Ross struct vattr va; 562613a2f6bSGordon Ross smbnode_t *np; 563613a2f6bSGordon Ross smbmntinfo_t *smi; 564613a2f6bSGordon Ross smb_share_t *ssp; 5659c9af259SGordon Ross offset_t endoff; 5669c9af259SGordon Ross ssize_t past_eof; 5679c9af259SGordon Ross int error; 5684bff34e3Sthurlow 5694bff34e3Sthurlow np = VTOSMB(vp); 5704bff34e3Sthurlow smi = VTOSMI(vp); 571613a2f6bSGordon Ross ssp = smi->smi_share; 5724bff34e3Sthurlow 5734bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 5744bff34e3Sthurlow return (EIO); 5754bff34e3Sthurlow 5764bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 5774bff34e3Sthurlow return (EIO); 5784bff34e3Sthurlow 5794bff34e3Sthurlow ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER)); 5804bff34e3Sthurlow 5814bff34e3Sthurlow if (vp->v_type != VREG) 5824bff34e3Sthurlow return (EISDIR); 5834bff34e3Sthurlow 5844bff34e3Sthurlow if (uiop->uio_resid == 0) 5854bff34e3Sthurlow return (0); 5864bff34e3Sthurlow 5874bff34e3Sthurlow /* 5884bff34e3Sthurlow * Like NFS3, just check for 63-bit overflow. 5894bff34e3Sthurlow * Our SMB layer takes care to return EFBIG 5904bff34e3Sthurlow * when it has to fallback to a 32-bit call. 5914bff34e3Sthurlow */ 592613a2f6bSGordon Ross endoff = uiop->uio_loffset + uiop->uio_resid; 593613a2f6bSGordon Ross if (uiop->uio_loffset < 0 || endoff < 0) 5944bff34e3Sthurlow return (EINVAL); 5954bff34e3Sthurlow 5964bff34e3Sthurlow /* get vnode attributes from server */ 5974bff34e3Sthurlow va.va_mask = AT_SIZE | AT_MTIME; 5984bff34e3Sthurlow if (error = smbfsgetattr(vp, &va, cr)) 5999c9af259SGordon Ross return (error); 6004bff34e3Sthurlow 6019c9af259SGordon Ross /* Update mtime with mtime from server here? */ 6029c9af259SGordon Ross 6039c9af259SGordon Ross /* if offset is beyond EOF, read nothing */ 6049c9af259SGordon Ross if (uiop->uio_loffset >= va.va_size) 6059c9af259SGordon Ross return (0); 6064bff34e3Sthurlow 6074bff34e3Sthurlow /* 6089c9af259SGordon Ross * Limit the read to the remaining file size. 6099c9af259SGordon Ross * Do this by temporarily reducing uio_resid 6109c9af259SGordon Ross * by the amount the lies beyoned the EOF. 6114bff34e3Sthurlow */ 6129c9af259SGordon Ross if (endoff > va.va_size) { 6139c9af259SGordon Ross past_eof = (ssize_t)(endoff - va.va_size); 6149c9af259SGordon Ross uiop->uio_resid -= past_eof; 6159c9af259SGordon Ross } else 6169c9af259SGordon Ross past_eof = 0; 6179c9af259SGordon Ross 6189c9af259SGordon Ross /* Shared lock for n_fid use in smb_rwuio */ 6199c9af259SGordon Ross if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) 6209c9af259SGordon Ross return (EINTR); 621613a2f6bSGordon Ross smb_credinit(&scred, cr); 6224bff34e3Sthurlow 623613a2f6bSGordon Ross /* After reconnect, n_fid is invalid */ 624613a2f6bSGordon Ross if (np->n_vcgenid != ssp->ss_vcgenid) 625613a2f6bSGordon Ross error = ESTALE; 626613a2f6bSGordon Ross else 627613a2f6bSGordon Ross error = smb_rwuio(ssp, np->n_fid, UIO_READ, 628613a2f6bSGordon Ross uiop, &scred, smb_timo_read); 6299c9af259SGordon Ross 6309c9af259SGordon Ross smb_credrele(&scred); 6314bff34e3Sthurlow smbfs_rw_exit(&np->r_lkserlock); 6324bff34e3Sthurlow 6339c9af259SGordon Ross /* undo adjustment of resid */ 6349c9af259SGordon Ross uiop->uio_resid += past_eof; 6359c9af259SGordon Ross 6369c9af259SGordon Ross return (error); 6374bff34e3Sthurlow } 6384bff34e3Sthurlow 6394bff34e3Sthurlow 6404bff34e3Sthurlow /* ARGSUSED */ 6414bff34e3Sthurlow static int 6424bff34e3Sthurlow smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr, 6434bff34e3Sthurlow caller_context_t *ct) 6444bff34e3Sthurlow { 6459c9af259SGordon Ross struct smb_cred scred; 6469c9af259SGordon Ross struct vattr va; 647613a2f6bSGordon Ross smbnode_t *np; 648613a2f6bSGordon Ross smbmntinfo_t *smi; 649613a2f6bSGordon Ross smb_share_t *ssp; 6509c9af259SGordon Ross offset_t endoff, limit; 6519c9af259SGordon Ross ssize_t past_limit; 6529c9af259SGordon Ross int error, timo; 6534bff34e3Sthurlow 6544bff34e3Sthurlow np = VTOSMB(vp); 6554bff34e3Sthurlow smi = VTOSMI(vp); 656613a2f6bSGordon Ross ssp = smi->smi_share; 6574bff34e3Sthurlow 6584bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 6594bff34e3Sthurlow return (EIO); 6604bff34e3Sthurlow 6614bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 6624bff34e3Sthurlow return (EIO); 6634bff34e3Sthurlow 6644bff34e3Sthurlow ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_WRITER)); 6654bff34e3Sthurlow 6664bff34e3Sthurlow if (vp->v_type != VREG) 6674bff34e3Sthurlow return (EISDIR); 6684bff34e3Sthurlow 6694bff34e3Sthurlow if (uiop->uio_resid == 0) 6704bff34e3Sthurlow return (0); 6714bff34e3Sthurlow 6729c9af259SGordon Ross /* 6739c9af259SGordon Ross * Handle ioflag bits: (FAPPEND|FSYNC|FDSYNC) 6749c9af259SGordon Ross */ 6759c9af259SGordon Ross if (ioflag & (FAPPEND | FSYNC)) { 6769c9af259SGordon Ross if (np->n_flag & NMODIFIED) { 677*02d09e03SGordon Ross smbfs_attrcache_remove(np); 6789c9af259SGordon Ross /* XXX: smbfs_vinvalbuf? */ 6799c9af259SGordon Ross } 6809c9af259SGordon Ross } 6819c9af259SGordon Ross if (ioflag & FAPPEND) { 6829c9af259SGordon Ross /* 6839c9af259SGordon Ross * File size can be changed by another client 6849c9af259SGordon Ross */ 6859c9af259SGordon Ross va.va_mask = AT_SIZE; 6869c9af259SGordon Ross if (error = smbfsgetattr(vp, &va, cr)) 6879c9af259SGordon Ross return (error); 6889c9af259SGordon Ross uiop->uio_loffset = va.va_size; 6899c9af259SGordon Ross } 6904bff34e3Sthurlow 6919c9af259SGordon Ross /* 6929c9af259SGordon Ross * Like NFS3, just check for 63-bit overflow. 6939c9af259SGordon Ross */ 6949c9af259SGordon Ross endoff = uiop->uio_loffset + uiop->uio_resid; 6959c9af259SGordon Ross if (uiop->uio_loffset < 0 || endoff < 0) 6969c9af259SGordon Ross return (EINVAL); 6974bff34e3Sthurlow 6984bff34e3Sthurlow /* 6999c9af259SGordon Ross * Check to make sure that the process will not exceed 7009c9af259SGordon Ross * its limit on file size. It is okay to write up to 7019c9af259SGordon Ross * the limit, but not beyond. Thus, the write which 7029c9af259SGordon Ross * reaches the limit will be short and the next write 7039c9af259SGordon Ross * will return an error. 7049c9af259SGordon Ross * 7059c9af259SGordon Ross * So if we're starting at or beyond the limit, EFBIG. 7069c9af259SGordon Ross * Otherwise, temporarily reduce resid to the amount 7079c9af259SGordon Ross * the falls after the limit. 7084bff34e3Sthurlow */ 7099c9af259SGordon Ross limit = uiop->uio_llimit; 7109c9af259SGordon Ross if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T) 7119c9af259SGordon Ross limit = MAXOFFSET_T; 7129c9af259SGordon Ross if (uiop->uio_loffset >= limit) 7139c9af259SGordon Ross return (EFBIG); 7149c9af259SGordon Ross if (endoff > limit) { 7159c9af259SGordon Ross past_limit = (ssize_t)(endoff - limit); 7169c9af259SGordon Ross uiop->uio_resid -= past_limit; 7179c9af259SGordon Ross } else 7189c9af259SGordon Ross past_limit = 0; 7199c9af259SGordon Ross 7209c9af259SGordon Ross /* Timeout: longer for append. */ 7219c9af259SGordon Ross timo = smb_timo_write; 722*02d09e03SGordon Ross if (endoff > np->r_size) 7239c9af259SGordon Ross timo = smb_timo_append; 7249c9af259SGordon Ross 7259c9af259SGordon Ross /* Shared lock for n_fid use in smb_rwuio */ 7269c9af259SGordon Ross if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) 7279c9af259SGordon Ross return (EINTR); 728613a2f6bSGordon Ross smb_credinit(&scred, cr); 7294bff34e3Sthurlow 730613a2f6bSGordon Ross /* After reconnect, n_fid is invalid */ 731613a2f6bSGordon Ross if (np->n_vcgenid != ssp->ss_vcgenid) 732613a2f6bSGordon Ross error = ESTALE; 733613a2f6bSGordon Ross else 734613a2f6bSGordon Ross error = smb_rwuio(ssp, np->n_fid, UIO_WRITE, 735613a2f6bSGordon Ross uiop, &scred, timo); 7369c9af259SGordon Ross 7379c9af259SGordon Ross if (error == 0) { 7389c9af259SGordon Ross mutex_enter(&np->r_statelock); 7399c9af259SGordon Ross np->n_flag |= (NFLUSHWIRE | NATTRCHANGED); 740*02d09e03SGordon Ross if (uiop->uio_loffset > (offset_t)np->r_size) 741*02d09e03SGordon Ross np->r_size = (len_t)uiop->uio_loffset; 7429c9af259SGordon Ross mutex_exit(&np->r_statelock); 7439c9af259SGordon Ross if (ioflag & (FSYNC|FDSYNC)) { 7449c9af259SGordon Ross /* Don't error the I/O if this fails. */ 7459c9af259SGordon Ross (void) smbfs_smb_flush(np, &scred); 7469c9af259SGordon Ross } 7479c9af259SGordon Ross } 7489c9af259SGordon Ross 7499c9af259SGordon Ross smb_credrele(&scred); 7504bff34e3Sthurlow smbfs_rw_exit(&np->r_lkserlock); 7514bff34e3Sthurlow 7529c9af259SGordon Ross /* undo adjustment of resid */ 7539c9af259SGordon Ross uiop->uio_resid += past_limit; 7549c9af259SGordon Ross 7559c9af259SGordon Ross return (error); 7564bff34e3Sthurlow } 7574bff34e3Sthurlow 7584bff34e3Sthurlow 7597568150aSgwr /* ARGSUSED */ 7607568150aSgwr static int 7617568150aSgwr smbfs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, 7627568150aSgwr cred_t *cr, int *rvalp, caller_context_t *ct) 7637568150aSgwr { 7647568150aSgwr int error; 7657568150aSgwr smbmntinfo_t *smi; 7667568150aSgwr 7677568150aSgwr smi = VTOSMI(vp); 7687568150aSgwr 7697568150aSgwr if (curproc->p_zone != smi->smi_zone) 7707568150aSgwr return (EIO); 7717568150aSgwr 7727568150aSgwr if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 7737568150aSgwr return (EIO); 7747568150aSgwr 7757568150aSgwr switch (cmd) { 7767568150aSgwr /* First three from ZFS. XXX - need these? */ 7777568150aSgwr 7787568150aSgwr case _FIOFFS: 7797568150aSgwr error = smbfs_fsync(vp, 0, cr, ct); 7807568150aSgwr break; 7817568150aSgwr 7827568150aSgwr /* 7837568150aSgwr * The following two ioctls are used by bfu. 7847568150aSgwr * Silently ignore to avoid bfu errors. 7857568150aSgwr */ 7867568150aSgwr case _FIOGDIO: 7877568150aSgwr case _FIOSDIO: 7887568150aSgwr error = 0; 7897568150aSgwr break; 7907568150aSgwr 7917568150aSgwr #ifdef NOT_YET /* XXX - from the NFS code. */ 7927568150aSgwr case _FIODIRECTIO: 7937568150aSgwr error = smbfs_directio(vp, (int)arg, cr); 7947568150aSgwr #endif 7957568150aSgwr 7967568150aSgwr /* 7977568150aSgwr * Allow get/set with "raw" security descriptor (SD) data. 7987568150aSgwr * Useful for testing, diagnosing idmap problems, etc. 7997568150aSgwr */ 8007568150aSgwr case SMBFSIO_GETSD: 8017568150aSgwr error = smbfs_ioc_getsd(vp, arg, flag, cr); 8027568150aSgwr break; 8037568150aSgwr 8047568150aSgwr case SMBFSIO_SETSD: 8057568150aSgwr error = smbfs_ioc_setsd(vp, arg, flag, cr); 8067568150aSgwr break; 8077568150aSgwr 8087568150aSgwr default: 8097568150aSgwr error = ENOTTY; 8107568150aSgwr break; 8117568150aSgwr } 8127568150aSgwr 8137568150aSgwr return (error); 8147568150aSgwr } 8157568150aSgwr 8167568150aSgwr 8174bff34e3Sthurlow /* 8184bff34e3Sthurlow * Return either cached or remote attributes. If get remote attr 8194bff34e3Sthurlow * use them to check and invalidate caches, then cache the new attributes. 8204bff34e3Sthurlow * 8214bff34e3Sthurlow * XXX 8224bff34e3Sthurlow * This op should eventually support PSARC 2007/315, Extensible Attribute 8234bff34e3Sthurlow * Interfaces, for richer metadata. 8244bff34e3Sthurlow */ 8254bff34e3Sthurlow /* ARGSUSED */ 8264bff34e3Sthurlow static int 8274bff34e3Sthurlow smbfs_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr, 8284bff34e3Sthurlow caller_context_t *ct) 8294bff34e3Sthurlow { 8304bff34e3Sthurlow smbnode_t *np; 8314bff34e3Sthurlow smbmntinfo_t *smi; 8324bff34e3Sthurlow 8334bff34e3Sthurlow smi = VTOSMI(vp); 8344bff34e3Sthurlow 8354bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 8364bff34e3Sthurlow return (EIO); 8374bff34e3Sthurlow 8384bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 8394bff34e3Sthurlow return (EIO); 8404bff34e3Sthurlow 8414bff34e3Sthurlow /* 8424bff34e3Sthurlow * If it has been specified that the return value will 8434bff34e3Sthurlow * just be used as a hint, and we are only being asked 8444bff34e3Sthurlow * for size, fsid or rdevid, then return the client's 8454bff34e3Sthurlow * notion of these values without checking to make sure 8464bff34e3Sthurlow * that the attribute cache is up to date. 8474bff34e3Sthurlow * The whole point is to avoid an over the wire GETATTR 8484bff34e3Sthurlow * call. 8494bff34e3Sthurlow */ 8504bff34e3Sthurlow np = VTOSMB(vp); 8514bff34e3Sthurlow if (flags & ATTR_HINT) { 8524bff34e3Sthurlow if (vap->va_mask == 8534bff34e3Sthurlow (vap->va_mask & (AT_SIZE | AT_FSID | AT_RDEV))) { 8544bff34e3Sthurlow mutex_enter(&np->r_statelock); 8554bff34e3Sthurlow if (vap->va_mask | AT_SIZE) 8564bff34e3Sthurlow vap->va_size = np->r_size; 8574bff34e3Sthurlow if (vap->va_mask | AT_FSID) 858*02d09e03SGordon Ross vap->va_fsid = vp->v_vfsp->vfs_dev; 8594bff34e3Sthurlow if (vap->va_mask | AT_RDEV) 860*02d09e03SGordon Ross vap->va_rdev = vp->v_rdev; 8614bff34e3Sthurlow mutex_exit(&np->r_statelock); 8624bff34e3Sthurlow return (0); 8634bff34e3Sthurlow } 8644bff34e3Sthurlow } 8654bff34e3Sthurlow 8664bff34e3Sthurlow return (smbfsgetattr(vp, vap, cr)); 8674bff34e3Sthurlow } 8684bff34e3Sthurlow 869*02d09e03SGordon Ross /* smbfsgetattr() in smbfs_client.c */ 8704bff34e3Sthurlow 8714bff34e3Sthurlow /* 8724bff34e3Sthurlow * XXX 8734bff34e3Sthurlow * This op should eventually support PSARC 2007/315, Extensible Attribute 8744bff34e3Sthurlow * Interfaces, for richer metadata. 8754bff34e3Sthurlow */ 8764bff34e3Sthurlow /*ARGSUSED4*/ 8774bff34e3Sthurlow static int 8784bff34e3Sthurlow smbfs_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr, 8794bff34e3Sthurlow caller_context_t *ct) 8804bff34e3Sthurlow { 881*02d09e03SGordon Ross vfs_t *vfsp; 882*02d09e03SGordon Ross smbmntinfo_t *smi; 8834bff34e3Sthurlow int error; 8844bff34e3Sthurlow uint_t mask; 8854bff34e3Sthurlow struct vattr oldva; 8864bff34e3Sthurlow 887*02d09e03SGordon Ross vfsp = vp->v_vfsp; 888*02d09e03SGordon Ross smi = VFTOSMI(vfsp); 8894bff34e3Sthurlow 8904bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 8914bff34e3Sthurlow return (EIO); 8924bff34e3Sthurlow 893*02d09e03SGordon Ross if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 8944bff34e3Sthurlow return (EIO); 8954bff34e3Sthurlow 8964bff34e3Sthurlow mask = vap->va_mask; 8974bff34e3Sthurlow if (mask & AT_NOSET) 8984bff34e3Sthurlow return (EINVAL); 8994bff34e3Sthurlow 900*02d09e03SGordon Ross if (vfsp->vfs_flag & VFS_RDONLY) 901*02d09e03SGordon Ross return (EROFS); 902*02d09e03SGordon Ross 903*02d09e03SGordon Ross bzero(&oldva, sizeof (oldva)); 9044bff34e3Sthurlow oldva.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID; 9054bff34e3Sthurlow error = smbfsgetattr(vp, &oldva, cr); 9064bff34e3Sthurlow if (error) 9074bff34e3Sthurlow return (error); 9084bff34e3Sthurlow 9094bff34e3Sthurlow error = secpolicy_vnode_setattr(cr, vp, vap, &oldva, flags, 9104bff34e3Sthurlow smbfs_accessx, vp); 9114bff34e3Sthurlow if (error) 9124bff34e3Sthurlow return (error); 9134bff34e3Sthurlow 9144bff34e3Sthurlow return (smbfssetattr(vp, vap, flags, cr)); 9154bff34e3Sthurlow } 9164bff34e3Sthurlow 9174bff34e3Sthurlow /* 9184bff34e3Sthurlow * Mostly from Darwin smbfs_setattr() 9194bff34e3Sthurlow * but then modified a lot. 9204bff34e3Sthurlow */ 9214bff34e3Sthurlow /* ARGSUSED */ 9224bff34e3Sthurlow static int 9234bff34e3Sthurlow smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr) 9244bff34e3Sthurlow { 9254bff34e3Sthurlow int error = 0; 9264bff34e3Sthurlow smbnode_t *np = VTOSMB(vp); 9274bff34e3Sthurlow uint_t mask = vap->va_mask; 9284bff34e3Sthurlow struct timespec *mtime, *atime; 9294bff34e3Sthurlow struct smb_cred scred; 9304bff34e3Sthurlow int cerror, modified = 0; 9314bff34e3Sthurlow unsigned short fid; 9324bff34e3Sthurlow int have_fid = 0; 9334bff34e3Sthurlow uint32_t rights = 0; 9344bff34e3Sthurlow 935*02d09e03SGordon Ross ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone); 9364bff34e3Sthurlow 93791d632c8Sgwr /* 93891d632c8Sgwr * There are no settable attributes on the XATTR dir, 93991d632c8Sgwr * so just silently ignore these. On XATTR files, 94091d632c8Sgwr * you can set the size but nothing else. 94191d632c8Sgwr */ 94291d632c8Sgwr if (vp->v_flag & V_XATTRDIR) 94391d632c8Sgwr return (0); 94491d632c8Sgwr if (np->n_flag & N_XATTR) { 94591d632c8Sgwr if (mask & AT_TIMES) 94691d632c8Sgwr SMBVDEBUG("ignore set time on xattr\n"); 94791d632c8Sgwr mask &= AT_SIZE; 94891d632c8Sgwr } 94991d632c8Sgwr 9504bff34e3Sthurlow /* 9514bff34e3Sthurlow * If our caller is trying to set multiple attributes, they 9524bff34e3Sthurlow * can make no assumption about what order they are done in. 9534bff34e3Sthurlow * Here we try to do them in order of decreasing likelihood 9544bff34e3Sthurlow * of failure, just to minimize the chance we'll wind up 9554bff34e3Sthurlow * with a partially complete request. 9564bff34e3Sthurlow */ 9574bff34e3Sthurlow 9584bff34e3Sthurlow /* Shared lock for (possible) n_fid use. */ 9594bff34e3Sthurlow if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) 9604bff34e3Sthurlow return (EINTR); 961613a2f6bSGordon Ross smb_credinit(&scred, cr); 9624bff34e3Sthurlow 9634bff34e3Sthurlow /* 9644bff34e3Sthurlow * Will we need an open handle for this setattr? 9654bff34e3Sthurlow * If so, what rights will we need? 9664bff34e3Sthurlow */ 9674bff34e3Sthurlow if (mask & (AT_ATIME | AT_MTIME)) { 9684bff34e3Sthurlow rights |= 969*02d09e03SGordon Ross SA_RIGHT_FILE_WRITE_ATTRIBUTES; 9704bff34e3Sthurlow } 9714bff34e3Sthurlow if (mask & AT_SIZE) { 9724bff34e3Sthurlow rights |= 9734bff34e3Sthurlow SA_RIGHT_FILE_WRITE_DATA | 9744bff34e3Sthurlow SA_RIGHT_FILE_APPEND_DATA; 975*02d09e03SGordon Ross } 976*02d09e03SGordon Ross 977*02d09e03SGordon Ross /* 978*02d09e03SGordon Ross * Only SIZE really requires a handle, but it's 979*02d09e03SGordon Ross * simpler and more reliable to set via a handle. 980*02d09e03SGordon Ross * Some servers like NT4 won't set times by path. 981*02d09e03SGordon Ross * Also, we're usually setting everything anyway. 982*02d09e03SGordon Ross */ 983*02d09e03SGordon Ross if (mask & (AT_SIZE | AT_ATIME | AT_MTIME)) { 9844bff34e3Sthurlow error = smbfs_smb_tmpopen(np, rights, &scred, &fid); 9854bff34e3Sthurlow if (error) { 9864bff34e3Sthurlow SMBVDEBUG("error %d opening %s\n", 9874bff34e3Sthurlow error, np->n_rpath); 9884bff34e3Sthurlow goto out; 9894bff34e3Sthurlow } 9904bff34e3Sthurlow have_fid = 1; 9914bff34e3Sthurlow } 9924bff34e3Sthurlow 9934bff34e3Sthurlow /* 9944bff34e3Sthurlow * If the server supports the UNIX extensions, right here is where 9954bff34e3Sthurlow * we'd support changes to uid, gid, mode, and possibly va_flags. 9964bff34e3Sthurlow * For now we claim to have made any such changes. 9974bff34e3Sthurlow */ 9984bff34e3Sthurlow 9994bff34e3Sthurlow if (mask & AT_SIZE) { 10004bff34e3Sthurlow /* 10014bff34e3Sthurlow * If the new file size is less than what the client sees as 10024bff34e3Sthurlow * the file size, then just change the size and invalidate 10034bff34e3Sthurlow * the pages. 10044bff34e3Sthurlow * I am commenting this code at present because the function 10054bff34e3Sthurlow * smbfs_putapage() is not yet implemented. 10064bff34e3Sthurlow */ 10074bff34e3Sthurlow 10084bff34e3Sthurlow /* 10094bff34e3Sthurlow * Set the file size to vap->va_size. 10104bff34e3Sthurlow */ 10114bff34e3Sthurlow ASSERT(have_fid); 10124bff34e3Sthurlow error = smbfs_smb_setfsize(np, fid, vap->va_size, &scred); 10134bff34e3Sthurlow if (error) { 10144bff34e3Sthurlow SMBVDEBUG("setsize error %d file %s\n", 10154bff34e3Sthurlow error, np->n_rpath); 10164bff34e3Sthurlow } else { 10174bff34e3Sthurlow /* 10184bff34e3Sthurlow * Darwin had code here to zero-extend. 10194bff34e3Sthurlow * Tests indicate the server will zero-fill, 10204bff34e3Sthurlow * so looks like we don't need to do this. 10214bff34e3Sthurlow * Good thing, as this could take forever. 1022613a2f6bSGordon Ross * 1023613a2f6bSGordon Ross * XXX: Reportedly, writing one byte of zero 1024613a2f6bSGordon Ross * at the end offset avoids problems here. 10254bff34e3Sthurlow */ 10264bff34e3Sthurlow mutex_enter(&np->r_statelock); 10274bff34e3Sthurlow np->r_size = vap->va_size; 10284bff34e3Sthurlow mutex_exit(&np->r_statelock); 10294bff34e3Sthurlow modified = 1; 10304bff34e3Sthurlow } 10314bff34e3Sthurlow } 10324bff34e3Sthurlow 10334bff34e3Sthurlow /* 10344bff34e3Sthurlow * XXX: When Solaris has create_time, set that too. 10354bff34e3Sthurlow * Note: create_time is different from ctime. 10364bff34e3Sthurlow */ 10374bff34e3Sthurlow mtime = ((mask & AT_MTIME) ? &vap->va_mtime : 0); 10384bff34e3Sthurlow atime = ((mask & AT_ATIME) ? &vap->va_atime : 0); 10394bff34e3Sthurlow 10404bff34e3Sthurlow if (mtime || atime) { 10414bff34e3Sthurlow /* 1042*02d09e03SGordon Ross * Always use the handle-based set attr call now. 1043*02d09e03SGordon Ross * Not trying to set DOS attributes here so pass zero. 10444bff34e3Sthurlow */ 1045*02d09e03SGordon Ross ASSERT(have_fid); 1046*02d09e03SGordon Ross error = smbfs_smb_setfattr(np, fid, 1047*02d09e03SGordon Ross 0, mtime, atime, &scred); 10484bff34e3Sthurlow if (error) { 10494bff34e3Sthurlow SMBVDEBUG("set times error %d file %s\n", 10504bff34e3Sthurlow error, np->n_rpath); 10514bff34e3Sthurlow } else { 10524bff34e3Sthurlow modified = 1; 10534bff34e3Sthurlow } 10544bff34e3Sthurlow } 10554bff34e3Sthurlow 10564bff34e3Sthurlow out: 10574bff34e3Sthurlow if (modified) { 10584bff34e3Sthurlow /* 1059*02d09e03SGordon Ross * Invalidate attribute cache in case the server 1060*02d09e03SGordon Ross * doesn't set exactly the attributes we asked. 10614bff34e3Sthurlow */ 1062*02d09e03SGordon Ross smbfs_attrcache_remove(np); 10634bff34e3Sthurlow } 10644bff34e3Sthurlow 10654bff34e3Sthurlow if (have_fid) { 10664bff34e3Sthurlow cerror = smbfs_smb_tmpclose(np, fid, &scred); 10674bff34e3Sthurlow if (cerror) 1068*02d09e03SGordon Ross SMBVDEBUG("error %d closing %s\n", 10694bff34e3Sthurlow cerror, np->n_rpath); 10704bff34e3Sthurlow } 10714bff34e3Sthurlow 10724bff34e3Sthurlow smb_credrele(&scred); 10734bff34e3Sthurlow smbfs_rw_exit(&np->r_lkserlock); 10744bff34e3Sthurlow 10754bff34e3Sthurlow return (error); 10764bff34e3Sthurlow } 10774bff34e3Sthurlow 10784bff34e3Sthurlow /* 10794bff34e3Sthurlow * smbfs_access_rwx() 10804bff34e3Sthurlow * Common function for smbfs_access, etc. 10814bff34e3Sthurlow * 10824bff34e3Sthurlow * The security model implemented by the FS is unusual 10834bff34e3Sthurlow * due to our "single user mounts" restriction. 10844bff34e3Sthurlow * 10854bff34e3Sthurlow * All access under a given mount point uses the CIFS 10864bff34e3Sthurlow * credentials established by the owner of the mount. 10874bff34e3Sthurlow * The Unix uid/gid/mode information is not (easily) 10884bff34e3Sthurlow * provided by CIFS, and is instead fabricated using 10894bff34e3Sthurlow * settings held in the mount structure. 10904bff34e3Sthurlow * 10914bff34e3Sthurlow * Most access checking is handled by the CIFS server, 10924bff34e3Sthurlow * but we need sufficient Unix access checks here to 10934bff34e3Sthurlow * prevent other local Unix users from having access 10944bff34e3Sthurlow * to objects under this mount that the uid/gid/mode 10954bff34e3Sthurlow * settings in the mount would not allow. 10964bff34e3Sthurlow * 10974bff34e3Sthurlow * With this model, there is a case where we need the 10984bff34e3Sthurlow * ability to do an access check before we have the 10994bff34e3Sthurlow * vnode for an object. This function takes advantage 11004bff34e3Sthurlow * of the fact that the uid/gid/mode is per mount, and 11014bff34e3Sthurlow * avoids the need for a vnode. 11024bff34e3Sthurlow * 11034bff34e3Sthurlow * We still (sort of) need a vnode when we call 11044bff34e3Sthurlow * secpolicy_vnode_access, but that only uses 11054bff34e3Sthurlow * the vtype field, so we can use a pair of fake 11064bff34e3Sthurlow * vnodes that have only v_type filled in. 11074bff34e3Sthurlow * 11084bff34e3Sthurlow * XXX: Later, add a new secpolicy_vtype_access() 11094bff34e3Sthurlow * that takes the vtype instead of a vnode, and 11104bff34e3Sthurlow * get rid of the tmpl_vxxx fake vnodes below. 11114bff34e3Sthurlow */ 11124bff34e3Sthurlow static int 11134bff34e3Sthurlow smbfs_access_rwx(vfs_t *vfsp, int vtype, int mode, cred_t *cr) 11144bff34e3Sthurlow { 11154bff34e3Sthurlow /* See the secpolicy call below. */ 11164bff34e3Sthurlow static const vnode_t tmpl_vdir = { .v_type = VDIR }; 11174bff34e3Sthurlow static const vnode_t tmpl_vreg = { .v_type = VREG }; 11184bff34e3Sthurlow vattr_t va; 11194bff34e3Sthurlow vnode_t *tvp; 11204bff34e3Sthurlow struct smbmntinfo *smi = VFTOSMI(vfsp); 11214bff34e3Sthurlow int shift = 0; 11224bff34e3Sthurlow 11234bff34e3Sthurlow /* 11244bff34e3Sthurlow * Build our (fabricated) vnode attributes. 11254bff34e3Sthurlow * XXX: Could make these templates in the 11264bff34e3Sthurlow * per-mount struct and use them here. 11274bff34e3Sthurlow */ 11284bff34e3Sthurlow bzero(&va, sizeof (va)); 11294bff34e3Sthurlow va.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID; 11304bff34e3Sthurlow va.va_type = vtype; 11314bff34e3Sthurlow va.va_mode = (vtype == VDIR) ? 1132*02d09e03SGordon Ross smi->smi_dmode : smi->smi_fmode; 1133*02d09e03SGordon Ross va.va_uid = smi->smi_uid; 1134*02d09e03SGordon Ross va.va_gid = smi->smi_gid; 11354bff34e3Sthurlow 11364bff34e3Sthurlow /* 11374bff34e3Sthurlow * Disallow write attempts on read-only file systems, 11384bff34e3Sthurlow * unless the file is a device or fifo node. Note: 11394bff34e3Sthurlow * Inline vn_is_readonly and IS_DEVVP here because 11404bff34e3Sthurlow * we may not have a vnode ptr. Original expr. was: 11414bff34e3Sthurlow * (mode & VWRITE) && vn_is_readonly(vp) && !IS_DEVVP(vp)) 11424bff34e3Sthurlow */ 11434bff34e3Sthurlow if ((mode & VWRITE) && 11444bff34e3Sthurlow (vfsp->vfs_flag & VFS_RDONLY) && 11454bff34e3Sthurlow !(vtype == VCHR || vtype == VBLK || vtype == VFIFO)) 11464bff34e3Sthurlow return (EROFS); 11474bff34e3Sthurlow 11484bff34e3Sthurlow /* 11494bff34e3Sthurlow * Disallow attempts to access mandatory lock files. 11504bff34e3Sthurlow * Similarly, expand MANDLOCK here. 11514bff34e3Sthurlow * XXX: not sure we need this. 11524bff34e3Sthurlow */ 11534bff34e3Sthurlow if ((mode & (VWRITE | VREAD | VEXEC)) && 11544bff34e3Sthurlow va.va_type == VREG && MANDMODE(va.va_mode)) 11554bff34e3Sthurlow return (EACCES); 11564bff34e3Sthurlow 11574bff34e3Sthurlow /* 11584bff34e3Sthurlow * Access check is based on only 11594bff34e3Sthurlow * one of owner, group, public. 11604bff34e3Sthurlow * If not owner, then check group. 11614bff34e3Sthurlow * If not a member of the group, 11624bff34e3Sthurlow * then check public access. 11634bff34e3Sthurlow */ 11644bff34e3Sthurlow if (crgetuid(cr) != va.va_uid) { 11654bff34e3Sthurlow shift += 3; 11664bff34e3Sthurlow if (!groupmember(va.va_gid, cr)) 11674bff34e3Sthurlow shift += 3; 11684bff34e3Sthurlow } 11694bff34e3Sthurlow mode &= ~(va.va_mode << shift); 11704bff34e3Sthurlow if (mode == 0) 11714bff34e3Sthurlow return (0); 11724bff34e3Sthurlow 11734bff34e3Sthurlow /* 11744bff34e3Sthurlow * We need a vnode for secpolicy_vnode_access, 11754bff34e3Sthurlow * but the only thing it looks at is v_type, 11764bff34e3Sthurlow * so pass one of the templates above. 11774bff34e3Sthurlow */ 11784bff34e3Sthurlow tvp = (va.va_type == VDIR) ? 11794bff34e3Sthurlow (vnode_t *)&tmpl_vdir : 11804bff34e3Sthurlow (vnode_t *)&tmpl_vreg; 11814bff34e3Sthurlow return (secpolicy_vnode_access(cr, tvp, va.va_uid, mode)); 11824bff34e3Sthurlow } 11834bff34e3Sthurlow 11844bff34e3Sthurlow /* 11854bff34e3Sthurlow * See smbfs_setattr 11864bff34e3Sthurlow */ 11874bff34e3Sthurlow static int 11884bff34e3Sthurlow smbfs_accessx(void *arg, int mode, cred_t *cr) 11894bff34e3Sthurlow { 11904bff34e3Sthurlow vnode_t *vp = arg; 11914bff34e3Sthurlow /* 11924bff34e3Sthurlow * Note: The caller has checked the current zone, 11934bff34e3Sthurlow * the SMI_DEAD and VFS_UNMOUNTED flags, etc. 11944bff34e3Sthurlow */ 11954bff34e3Sthurlow return (smbfs_access_rwx(vp->v_vfsp, vp->v_type, mode, cr)); 11964bff34e3Sthurlow } 11974bff34e3Sthurlow 11984bff34e3Sthurlow /* 11994bff34e3Sthurlow * XXX 12004bff34e3Sthurlow * This op should support PSARC 2007/403, Modified Access Checks for CIFS 12014bff34e3Sthurlow */ 12024bff34e3Sthurlow /* ARGSUSED */ 12034bff34e3Sthurlow static int 12044bff34e3Sthurlow smbfs_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct) 12054bff34e3Sthurlow { 12064bff34e3Sthurlow vfs_t *vfsp; 12074bff34e3Sthurlow smbmntinfo_t *smi; 12084bff34e3Sthurlow 12094bff34e3Sthurlow vfsp = vp->v_vfsp; 12104bff34e3Sthurlow smi = VFTOSMI(vfsp); 12114bff34e3Sthurlow 12124bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 12134bff34e3Sthurlow return (EIO); 12144bff34e3Sthurlow 12154bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 12164bff34e3Sthurlow return (EIO); 12174bff34e3Sthurlow 12184bff34e3Sthurlow return (smbfs_access_rwx(vfsp, vp->v_type, mode, cr)); 12194bff34e3Sthurlow } 12204bff34e3Sthurlow 12214bff34e3Sthurlow 12224bff34e3Sthurlow /* 12234bff34e3Sthurlow * Flush local dirty pages to stable storage on the server. 12244bff34e3Sthurlow * 12254bff34e3Sthurlow * If FNODSYNC is specified, then there is nothing to do because 12264bff34e3Sthurlow * metadata changes are not cached on the client before being 12274bff34e3Sthurlow * sent to the server. 12284bff34e3Sthurlow */ 12294bff34e3Sthurlow /* ARGSUSED */ 12304bff34e3Sthurlow static int 12314bff34e3Sthurlow smbfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct) 12324bff34e3Sthurlow { 12334bff34e3Sthurlow int error = 0; 12344bff34e3Sthurlow smbmntinfo_t *smi; 12352f5e3e91SGordon Ross smbnode_t *np; 12362f5e3e91SGordon Ross struct smb_cred scred; 12374bff34e3Sthurlow 12382f5e3e91SGordon Ross np = VTOSMB(vp); 12394bff34e3Sthurlow smi = VTOSMI(vp); 12404bff34e3Sthurlow 12414bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 12424bff34e3Sthurlow return (EIO); 12434bff34e3Sthurlow 12444bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 12454bff34e3Sthurlow return (EIO); 12464bff34e3Sthurlow 12474bff34e3Sthurlow if ((syncflag & FNODSYNC) || IS_SWAPVP(vp)) 12484bff34e3Sthurlow return (0); 12494bff34e3Sthurlow 12502f5e3e91SGordon Ross if ((syncflag & (FSYNC|FDSYNC)) == 0) 12512f5e3e91SGordon Ross return (0); 12522f5e3e91SGordon Ross 12532f5e3e91SGordon Ross /* Shared lock for n_fid use in _flush */ 12542f5e3e91SGordon Ross if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) 12552f5e3e91SGordon Ross return (EINTR); 1256613a2f6bSGordon Ross smb_credinit(&scred, cr); 12572f5e3e91SGordon Ross 12582f5e3e91SGordon Ross error = smbfs_smb_flush(np, &scred); 12592f5e3e91SGordon Ross 12602f5e3e91SGordon Ross smb_credrele(&scred); 12612f5e3e91SGordon Ross smbfs_rw_exit(&np->r_lkserlock); 12622f5e3e91SGordon Ross 12634bff34e3Sthurlow return (error); 12644bff34e3Sthurlow } 12654bff34e3Sthurlow 12664bff34e3Sthurlow /* 12674bff34e3Sthurlow * Last reference to vnode went away. 12684bff34e3Sthurlow */ 12694bff34e3Sthurlow /* ARGSUSED */ 12704bff34e3Sthurlow static void 12714bff34e3Sthurlow smbfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct) 12724bff34e3Sthurlow { 12734bff34e3Sthurlow smbnode_t *np; 12744bff34e3Sthurlow 12754bff34e3Sthurlow /* 12764bff34e3Sthurlow * Don't "bail out" for VFS_UNMOUNTED here, 12774bff34e3Sthurlow * as we want to do cleanup, etc. 12784bff34e3Sthurlow * See also pcfs_inactive 12794bff34e3Sthurlow */ 12804bff34e3Sthurlow 12814bff34e3Sthurlow np = VTOSMB(vp); 12824bff34e3Sthurlow 12834bff34e3Sthurlow /* 12844bff34e3Sthurlow * If this is coming from the wrong zone, we let someone in the right 12854bff34e3Sthurlow * zone take care of it asynchronously. We can get here due to 12864bff34e3Sthurlow * VN_RELE() being called from pageout() or fsflush(). This call may 12874bff34e3Sthurlow * potentially turn into an expensive no-op if, for instance, v_count 12884bff34e3Sthurlow * gets incremented in the meantime, but it's still correct. 12894bff34e3Sthurlow */ 12904bff34e3Sthurlow 12914bff34e3Sthurlow /* 12924bff34e3Sthurlow * Some paranoia from the Darwin code: 12934bff34e3Sthurlow * Make sure the FID was closed. 12944bff34e3Sthurlow * If we see this, it's a bug! 12954bff34e3Sthurlow * 12964bff34e3Sthurlow * No rw_enter here, as this should be the 12974bff34e3Sthurlow * last ref, and we're just looking... 12984bff34e3Sthurlow */ 12994bff34e3Sthurlow if (np->n_fidrefs > 0) { 13004bff34e3Sthurlow SMBVDEBUG("opencount %d fid %d file %s\n", 13014bff34e3Sthurlow np->n_fidrefs, np->n_fid, np->n_rpath); 13024bff34e3Sthurlow } 13034bff34e3Sthurlow if (np->n_dirrefs > 0) { 13044bff34e3Sthurlow uint_t fid = (np->n_dirseq) ? 13054bff34e3Sthurlow np->n_dirseq->f_Sid : 0; 13064bff34e3Sthurlow SMBVDEBUG("opencount %d fid %d dir %s\n", 13074bff34e3Sthurlow np->n_dirrefs, fid, np->n_rpath); 13084bff34e3Sthurlow } 13094bff34e3Sthurlow 1310*02d09e03SGordon Ross smbfs_addfree(np); 13114bff34e3Sthurlow } 13124bff34e3Sthurlow 13134bff34e3Sthurlow /* 13144bff34e3Sthurlow * Remote file system operations having to do with directory manipulation. 13154bff34e3Sthurlow */ 13164bff34e3Sthurlow /* ARGSUSED */ 13174bff34e3Sthurlow static int 13184bff34e3Sthurlow smbfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp, 13194bff34e3Sthurlow int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct, 13204bff34e3Sthurlow int *direntflags, pathname_t *realpnp) 13214bff34e3Sthurlow { 132291d632c8Sgwr vfs_t *vfs; 13234bff34e3Sthurlow smbmntinfo_t *smi; 132491d632c8Sgwr smbnode_t *dnp; 132591d632c8Sgwr int error; 13264bff34e3Sthurlow 132791d632c8Sgwr vfs = dvp->v_vfsp; 132891d632c8Sgwr smi = VFTOSMI(vfs); 13294bff34e3Sthurlow 13304bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 13314bff34e3Sthurlow return (EPERM); 13324bff34e3Sthurlow 133391d632c8Sgwr if (smi->smi_flags & SMI_DEAD || vfs->vfs_flag & VFS_UNMOUNTED) 13344bff34e3Sthurlow return (EIO); 13354bff34e3Sthurlow 13364bff34e3Sthurlow dnp = VTOSMB(dvp); 133791d632c8Sgwr 133891d632c8Sgwr /* 133991d632c8Sgwr * Are we looking up extended attributes? If so, "dvp" is 134091d632c8Sgwr * the file or directory for which we want attributes, and 134191d632c8Sgwr * we need a lookup of the (faked up) attribute directory 134291d632c8Sgwr * before we lookup the rest of the path. 134391d632c8Sgwr */ 134491d632c8Sgwr if (flags & LOOKUP_XATTR) { 134591d632c8Sgwr /* 134691d632c8Sgwr * Require the xattr mount option. 134791d632c8Sgwr */ 134891d632c8Sgwr if ((vfs->vfs_flag & VFS_XATTR) == 0) 134991d632c8Sgwr return (EINVAL); 135091d632c8Sgwr 135191d632c8Sgwr error = smbfs_get_xattrdir(dvp, vpp, cr, flags); 135291d632c8Sgwr return (error); 135391d632c8Sgwr } 135491d632c8Sgwr 1355*02d09e03SGordon Ross if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_READER, SMBINTR(dvp))) 1356*02d09e03SGordon Ross return (EINTR); 13574bff34e3Sthurlow 13584bff34e3Sthurlow error = smbfslookup(dvp, nm, vpp, cr, 1, ct); 13594bff34e3Sthurlow 13604bff34e3Sthurlow smbfs_rw_exit(&dnp->r_rwlock); 13614bff34e3Sthurlow 13624bff34e3Sthurlow return (error); 13634bff34e3Sthurlow } 13644bff34e3Sthurlow 13654bff34e3Sthurlow /* ARGSUSED */ 13664bff34e3Sthurlow static int 1367*02d09e03SGordon Ross smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, 1368*02d09e03SGordon Ross int cache_ok, caller_context_t *ct) 13694bff34e3Sthurlow { 13704bff34e3Sthurlow int error; 13714bff34e3Sthurlow int supplen; /* supported length */ 13724bff34e3Sthurlow vnode_t *vp; 1373*02d09e03SGordon Ross smbnode_t *np; 13744bff34e3Sthurlow smbnode_t *dnp; 13754bff34e3Sthurlow smbmntinfo_t *smi; 13764bff34e3Sthurlow /* struct smb_vc *vcp; */ 137791d632c8Sgwr const char *ill; 13784bff34e3Sthurlow const char *name = (const char *)nm; 13794bff34e3Sthurlow int nmlen = strlen(nm); 13804bff34e3Sthurlow int rplen; 13814bff34e3Sthurlow struct smb_cred scred; 13824bff34e3Sthurlow struct smbfattr fa; 13834bff34e3Sthurlow 13844bff34e3Sthurlow smi = VTOSMI(dvp); 13854bff34e3Sthurlow dnp = VTOSMB(dvp); 13864bff34e3Sthurlow 13874bff34e3Sthurlow ASSERT(curproc->p_zone == smi->smi_zone); 13884bff34e3Sthurlow 13894bff34e3Sthurlow #ifdef NOT_YET 13904bff34e3Sthurlow vcp = SSTOVC(smi->smi_share); 13914bff34e3Sthurlow 13924bff34e3Sthurlow /* XXX: Should compute this once and store it in smbmntinfo_t */ 13934bff34e3Sthurlow supplen = (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) ? 255 : 12; 13944bff34e3Sthurlow #else 13954bff34e3Sthurlow supplen = 255; 13964bff34e3Sthurlow #endif 13974bff34e3Sthurlow 13984bff34e3Sthurlow /* 13994bff34e3Sthurlow * RWlock must be held, either reader or writer. 14004bff34e3Sthurlow * XXX: Can we check without looking directly 14014bff34e3Sthurlow * inside the struct smbfs_rwlock_t? 14024bff34e3Sthurlow */ 14034bff34e3Sthurlow ASSERT(dnp->r_rwlock.count != 0); 14044bff34e3Sthurlow 14054bff34e3Sthurlow /* 1406*02d09e03SGordon Ross * If lookup is for "", just return dvp. 1407*02d09e03SGordon Ross * No need to perform any access checks. 14084bff34e3Sthurlow */ 14094bff34e3Sthurlow if (nmlen == 0) { 14104bff34e3Sthurlow VN_HOLD(dvp); 14114bff34e3Sthurlow *vpp = dvp; 14124bff34e3Sthurlow return (0); 14134bff34e3Sthurlow } 14144bff34e3Sthurlow 14154bff34e3Sthurlow /* 141691d632c8Sgwr * Can't do lookups in non-directories. 14174bff34e3Sthurlow */ 14184bff34e3Sthurlow if (dvp->v_type != VDIR) 14194bff34e3Sthurlow return (ENOTDIR); 14204bff34e3Sthurlow 142191d632c8Sgwr /* 142291d632c8Sgwr * Need search permission in the directory. 142391d632c8Sgwr */ 14244bff34e3Sthurlow error = smbfs_access(dvp, VEXEC, 0, cr, ct); 14254bff34e3Sthurlow if (error) 14264bff34e3Sthurlow return (error); 14274bff34e3Sthurlow 14284bff34e3Sthurlow /* 1429*02d09e03SGordon Ross * If lookup is for ".", just return dvp. 1430*02d09e03SGordon Ross * Access check was done above. 14314bff34e3Sthurlow */ 14324bff34e3Sthurlow if (nmlen == 1 && name[0] == '.') { 14334bff34e3Sthurlow VN_HOLD(dvp); 14344bff34e3Sthurlow *vpp = dvp; 14354bff34e3Sthurlow return (0); 14364bff34e3Sthurlow } 14374bff34e3Sthurlow 14384bff34e3Sthurlow /* 143991d632c8Sgwr * Now some sanity checks on the name. 144091d632c8Sgwr * First check the length. 14414bff34e3Sthurlow */ 144291d632c8Sgwr if (nmlen > supplen) 144391d632c8Sgwr return (ENAMETOOLONG); 144491d632c8Sgwr 144591d632c8Sgwr /* 144691d632c8Sgwr * Avoid surprises with characters that are 144791d632c8Sgwr * illegal in Windows file names. 144891d632c8Sgwr * Todo: CATIA mappings XXX 144991d632c8Sgwr */ 145091d632c8Sgwr ill = illegal_chars; 145191d632c8Sgwr if (dnp->n_flag & N_XATTR) 145291d632c8Sgwr ill++; /* allow colon */ 145391d632c8Sgwr if (strpbrk(nm, ill)) 145491d632c8Sgwr return (EINVAL); 145591d632c8Sgwr 14564bff34e3Sthurlow /* 1457*02d09e03SGordon Ross * Special handling for lookup of ".." 14584bff34e3Sthurlow * 14594bff34e3Sthurlow * We keep full pathnames (as seen on the server) 14604bff34e3Sthurlow * so we can just trim off the last component to 14614bff34e3Sthurlow * get the full pathname of the parent. Note: 14624bff34e3Sthurlow * We don't actually copy and modify, but just 14634bff34e3Sthurlow * compute the trimmed length and pass that with 14644bff34e3Sthurlow * the current dir path (not null terminated). 14654bff34e3Sthurlow * 14664bff34e3Sthurlow * We don't go over-the-wire to get attributes 14674bff34e3Sthurlow * for ".." because we know it's a directory, 14684bff34e3Sthurlow * and we can just leave the rest "stale" 14694bff34e3Sthurlow * until someone does a getattr. 14704bff34e3Sthurlow */ 14714bff34e3Sthurlow if (nmlen == 2 && name[0] == '.' && name[1] == '.') { 14724bff34e3Sthurlow if (dvp->v_flag & VROOT) { 14734bff34e3Sthurlow /* 14744bff34e3Sthurlow * Already at the root. This can happen 14754bff34e3Sthurlow * with directory listings at the root, 14764bff34e3Sthurlow * which lookup "." and ".." to get the 14774bff34e3Sthurlow * inode numbers. Let ".." be the same 14784bff34e3Sthurlow * as "." in the FS root. 14794bff34e3Sthurlow */ 14804bff34e3Sthurlow VN_HOLD(dvp); 14814bff34e3Sthurlow *vpp = dvp; 14824bff34e3Sthurlow return (0); 14834bff34e3Sthurlow } 14844bff34e3Sthurlow 148591d632c8Sgwr /* 148691d632c8Sgwr * Special case for XATTR directory 148791d632c8Sgwr */ 148891d632c8Sgwr if (dvp->v_flag & V_XATTRDIR) { 148991d632c8Sgwr error = smbfs_xa_parent(dvp, vpp); 149091d632c8Sgwr return (error); 149191d632c8Sgwr } 149291d632c8Sgwr 14934bff34e3Sthurlow /* 14944bff34e3Sthurlow * Find the parent path length. 14954bff34e3Sthurlow */ 14964bff34e3Sthurlow rplen = dnp->n_rplen; 14974bff34e3Sthurlow ASSERT(rplen > 0); 14984bff34e3Sthurlow while (--rplen >= 0) { 14994bff34e3Sthurlow if (dnp->n_rpath[rplen] == '\\') 15004bff34e3Sthurlow break; 15014bff34e3Sthurlow } 1502*02d09e03SGordon Ross if (rplen <= 0) { 15034bff34e3Sthurlow /* Found our way to the root. */ 15044bff34e3Sthurlow vp = SMBTOV(smi->smi_root); 15054bff34e3Sthurlow VN_HOLD(vp); 15064bff34e3Sthurlow *vpp = vp; 15074bff34e3Sthurlow return (0); 15084bff34e3Sthurlow } 1509*02d09e03SGordon Ross np = smbfs_node_findcreate(smi, 1510*02d09e03SGordon Ross dnp->n_rpath, rplen, NULL, 0, 0, 1511*02d09e03SGordon Ross &smbfs_fattr0); /* force create */ 1512*02d09e03SGordon Ross ASSERT(np != NULL); 1513*02d09e03SGordon Ross vp = SMBTOV(np); 15144bff34e3Sthurlow vp->v_type = VDIR; 15154bff34e3Sthurlow 15164bff34e3Sthurlow /* Success! */ 15174bff34e3Sthurlow *vpp = vp; 15184bff34e3Sthurlow return (0); 15194bff34e3Sthurlow } 15204bff34e3Sthurlow 15214bff34e3Sthurlow /* 1522*02d09e03SGordon Ross * Normal lookup of a name under this directory. 1523*02d09e03SGordon Ross * Note we handled "", ".", ".." above. 1524*02d09e03SGordon Ross */ 1525*02d09e03SGordon Ross if (cache_ok) { 1526*02d09e03SGordon Ross /* 1527*02d09e03SGordon Ross * The caller indicated that it's OK to use a 1528*02d09e03SGordon Ross * cached result for this lookup, so try to 1529*02d09e03SGordon Ross * reclaim a node from the smbfs node cache. 1530*02d09e03SGordon Ross */ 1531*02d09e03SGordon Ross error = smbfslookup_cache(dvp, nm, nmlen, &vp, cr); 1532*02d09e03SGordon Ross if (error) 1533*02d09e03SGordon Ross return (error); 1534*02d09e03SGordon Ross if (vp != NULL) { 1535*02d09e03SGordon Ross /* hold taken in lookup_cache */ 1536*02d09e03SGordon Ross *vpp = vp; 1537*02d09e03SGordon Ross return (0); 1538*02d09e03SGordon Ross } 1539*02d09e03SGordon Ross } 1540*02d09e03SGordon Ross 1541*02d09e03SGordon Ross /* 1542*02d09e03SGordon Ross * OK, go over-the-wire to get the attributes, 1543*02d09e03SGordon Ross * then create the node. 15444bff34e3Sthurlow */ 1545613a2f6bSGordon Ross smb_credinit(&scred, cr); 15464bff34e3Sthurlow /* Note: this can allocate a new "name" */ 15474bff34e3Sthurlow error = smbfs_smb_lookup(dnp, &name, &nmlen, &fa, &scred); 15484bff34e3Sthurlow smb_credrele(&scred); 1549*02d09e03SGordon Ross if (error == ENOTDIR) { 1550*02d09e03SGordon Ross /* 1551*02d09e03SGordon Ross * Lookup failed because this directory was 1552*02d09e03SGordon Ross * removed or renamed by another client. 1553*02d09e03SGordon Ross * Remove any cached attributes under it. 1554*02d09e03SGordon Ross */ 1555*02d09e03SGordon Ross smbfs_attrcache_remove(dnp); 1556*02d09e03SGordon Ross smbfs_attrcache_prune(dnp); 1557*02d09e03SGordon Ross } 15584bff34e3Sthurlow if (error) 15594bff34e3Sthurlow goto out; 15604bff34e3Sthurlow 15614bff34e3Sthurlow error = smbfs_nget(dvp, name, nmlen, &fa, &vp); 15624bff34e3Sthurlow if (error) 15634bff34e3Sthurlow goto out; 15644bff34e3Sthurlow 15654bff34e3Sthurlow /* Success! */ 15664bff34e3Sthurlow *vpp = vp; 15674bff34e3Sthurlow 15684bff34e3Sthurlow out: 15694bff34e3Sthurlow /* smbfs_smb_lookup may have allocated name. */ 15704bff34e3Sthurlow if (name != nm) 15714bff34e3Sthurlow smbfs_name_free(name, nmlen); 15724bff34e3Sthurlow 15734bff34e3Sthurlow return (error); 15744bff34e3Sthurlow } 15754bff34e3Sthurlow 1576*02d09e03SGordon Ross /* 1577*02d09e03SGordon Ross * smbfslookup_cache 1578*02d09e03SGordon Ross * 1579*02d09e03SGordon Ross * Try to reclaim a node from the smbfs node cache. 1580*02d09e03SGordon Ross * Some statistics for DEBUG. 1581*02d09e03SGordon Ross * 1582*02d09e03SGordon Ross * This mechanism lets us avoid many of the five (or more) 1583*02d09e03SGordon Ross * OtW lookup calls per file seen with "ls -l" if we search 1584*02d09e03SGordon Ross * the smbfs node cache for recently inactive(ated) nodes. 1585*02d09e03SGordon Ross */ 158691d632c8Sgwr #ifdef DEBUG 1587*02d09e03SGordon Ross int smbfs_lookup_cache_calls = 0; 1588*02d09e03SGordon Ross int smbfs_lookup_cache_error = 0; 1589*02d09e03SGordon Ross int smbfs_lookup_cache_miss = 0; 1590*02d09e03SGordon Ross int smbfs_lookup_cache_stale = 0; 1591*02d09e03SGordon Ross int smbfs_lookup_cache_hits = 0; 1592*02d09e03SGordon Ross #endif /* DEBUG */ 159391d632c8Sgwr 159491d632c8Sgwr /* ARGSUSED */ 159591d632c8Sgwr static int 1596*02d09e03SGordon Ross smbfslookup_cache(vnode_t *dvp, char *nm, int nmlen, 1597*02d09e03SGordon Ross vnode_t **vpp, cred_t *cr) 159891d632c8Sgwr { 159991d632c8Sgwr struct vattr va; 160091d632c8Sgwr smbnode_t *dnp; 1601*02d09e03SGordon Ross smbnode_t *np; 1602*02d09e03SGordon Ross vnode_t *vp; 1603*02d09e03SGordon Ross int error; 1604*02d09e03SGordon Ross char sep; 160591d632c8Sgwr 160691d632c8Sgwr dnp = VTOSMB(dvp); 1607*02d09e03SGordon Ross *vpp = NULL; 160891d632c8Sgwr 1609*02d09e03SGordon Ross #ifdef DEBUG 1610*02d09e03SGordon Ross smbfs_lookup_cache_calls++; 1611*02d09e03SGordon Ross #endif 161291d632c8Sgwr 161391d632c8Sgwr /* 1614*02d09e03SGordon Ross * First make sure we can get attributes for the 1615*02d09e03SGordon Ross * directory. Cached attributes are OK here. 1616*02d09e03SGordon Ross * If we removed or renamed the directory, this 1617*02d09e03SGordon Ross * will return ENOENT. If someone else removed 1618*02d09e03SGordon Ross * this directory or file, we'll find out when we 1619*02d09e03SGordon Ross * try to open or get attributes. 162091d632c8Sgwr */ 1621*02d09e03SGordon Ross va.va_mask = AT_TYPE | AT_MODE; 1622*02d09e03SGordon Ross error = smbfsgetattr(dvp, &va, cr); 1623*02d09e03SGordon Ross if (error) { 162491d632c8Sgwr #ifdef DEBUG 1625*02d09e03SGordon Ross smbfs_lookup_cache_error++; 162691d632c8Sgwr #endif 1627*02d09e03SGordon Ross return (error); 1628*02d09e03SGordon Ross } 1629*02d09e03SGordon Ross 1630*02d09e03SGordon Ross /* 1631*02d09e03SGordon Ross * Passing NULL smbfattr here so we will 1632*02d09e03SGordon Ross * just look, not create. 1633*02d09e03SGordon Ross */ 1634*02d09e03SGordon Ross sep = SMBFS_DNP_SEP(dnp); 1635*02d09e03SGordon Ross np = smbfs_node_findcreate(dnp->n_mount, 1636*02d09e03SGordon Ross dnp->n_rpath, dnp->n_rplen, 1637*02d09e03SGordon Ross nm, nmlen, sep, NULL); 1638*02d09e03SGordon Ross if (np == NULL) { 163991d632c8Sgwr #ifdef DEBUG 1640*02d09e03SGordon Ross smbfs_lookup_cache_miss++; 164191d632c8Sgwr #endif 1642*02d09e03SGordon Ross return (0); 1643*02d09e03SGordon Ross } 1644*02d09e03SGordon Ross 1645*02d09e03SGordon Ross /* 1646*02d09e03SGordon Ross * Found it. Attributes still valid? 1647*02d09e03SGordon Ross */ 1648*02d09e03SGordon Ross vp = SMBTOV(np); 1649*02d09e03SGordon Ross if (np->r_attrtime <= gethrtime()) { 1650*02d09e03SGordon Ross /* stale */ 165191d632c8Sgwr #ifdef DEBUG 1652*02d09e03SGordon Ross smbfs_lookup_cache_stale++; 165391d632c8Sgwr #endif 1654*02d09e03SGordon Ross VN_RELE(vp); 1655*02d09e03SGordon Ross return (0); 165691d632c8Sgwr } 1657*02d09e03SGordon Ross 1658*02d09e03SGordon Ross /* 1659*02d09e03SGordon Ross * Success! 1660*02d09e03SGordon Ross * Caller gets hold from smbfs_node_findcreate 1661*02d09e03SGordon Ross */ 166291d632c8Sgwr #ifdef DEBUG 1663*02d09e03SGordon Ross smbfs_lookup_cache_hits++; 166491d632c8Sgwr #endif 1665*02d09e03SGordon Ross *vpp = vp; 166691d632c8Sgwr return (0); 166791d632c8Sgwr } 166891d632c8Sgwr 16694bff34e3Sthurlow /* 16704bff34e3Sthurlow * XXX 16714bff34e3Sthurlow * vsecattr_t is new to build 77, and we need to eventually support 16724bff34e3Sthurlow * it in order to create an ACL when an object is created. 16734bff34e3Sthurlow * 16744bff34e3Sthurlow * This op should support the new FIGNORECASE flag for case-insensitive 16754bff34e3Sthurlow * lookups, per PSARC 2007/244. 16764bff34e3Sthurlow */ 16774bff34e3Sthurlow /* ARGSUSED */ 16784bff34e3Sthurlow static int 16794bff34e3Sthurlow smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive, 16804bff34e3Sthurlow int mode, vnode_t **vpp, cred_t *cr, int lfaware, caller_context_t *ct, 16814bff34e3Sthurlow vsecattr_t *vsecp) 16824bff34e3Sthurlow { 16834bff34e3Sthurlow int error; 16844bff34e3Sthurlow int cerror; 16854bff34e3Sthurlow vfs_t *vfsp; 16864bff34e3Sthurlow vnode_t *vp; 16874bff34e3Sthurlow #ifdef NOT_YET 16884bff34e3Sthurlow smbnode_t *np; 16894bff34e3Sthurlow #endif 16904bff34e3Sthurlow smbnode_t *dnp; 16914bff34e3Sthurlow smbmntinfo_t *smi; 16924bff34e3Sthurlow struct vattr vattr; 16934bff34e3Sthurlow struct smbfattr fattr; 16944bff34e3Sthurlow struct smb_cred scred; 16954bff34e3Sthurlow const char *name = (const char *)nm; 16964bff34e3Sthurlow int nmlen = strlen(nm); 16974bff34e3Sthurlow uint32_t disp; 16984bff34e3Sthurlow uint16_t fid; 169991d632c8Sgwr int xattr; 17004bff34e3Sthurlow 17014bff34e3Sthurlow vfsp = dvp->v_vfsp; 17024bff34e3Sthurlow smi = VFTOSMI(vfsp); 17034bff34e3Sthurlow dnp = VTOSMB(dvp); 17044bff34e3Sthurlow vp = NULL; 17054bff34e3Sthurlow 17064bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 17074bff34e3Sthurlow return (EPERM); 17084bff34e3Sthurlow 17094bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 17104bff34e3Sthurlow return (EIO); 17114bff34e3Sthurlow 17124bff34e3Sthurlow /* 17134bff34e3Sthurlow * Note: this may break mknod(2) calls to create a directory, 17144bff34e3Sthurlow * but that's obscure use. Some other filesystems do this. 17154bff34e3Sthurlow * XXX: Later, redirect VDIR type here to _mkdir. 17164bff34e3Sthurlow */ 17174bff34e3Sthurlow if (va->va_type != VREG) 17184bff34e3Sthurlow return (EINVAL); 17194bff34e3Sthurlow 17204bff34e3Sthurlow /* 17214bff34e3Sthurlow * If the pathname is "", just use dvp, no checks. 17224bff34e3Sthurlow * Do this outside of the rwlock (like zfs). 17234bff34e3Sthurlow */ 17244bff34e3Sthurlow if (nmlen == 0) { 17254bff34e3Sthurlow VN_HOLD(dvp); 17264bff34e3Sthurlow *vpp = dvp; 17274bff34e3Sthurlow return (0); 17284bff34e3Sthurlow } 17294bff34e3Sthurlow 17304bff34e3Sthurlow /* Don't allow "." or ".." through here. */ 17314bff34e3Sthurlow if ((nmlen == 1 && name[0] == '.') || 17324bff34e3Sthurlow (nmlen == 2 && name[0] == '.' && name[1] == '.')) 17334bff34e3Sthurlow return (EISDIR); 17344bff34e3Sthurlow 17354bff34e3Sthurlow /* 17364bff34e3Sthurlow * We make a copy of the attributes because the caller does not 17374bff34e3Sthurlow * expect us to change what va points to. 17384bff34e3Sthurlow */ 17394bff34e3Sthurlow vattr = *va; 17404bff34e3Sthurlow 17414bff34e3Sthurlow if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp))) 17424bff34e3Sthurlow return (EINTR); 1743613a2f6bSGordon Ross smb_credinit(&scred, cr); 17444bff34e3Sthurlow 17454bff34e3Sthurlow /* 17464bff34e3Sthurlow * XXX: Do we need r_lkserlock too? 17474bff34e3Sthurlow * No use of any shared fid or fctx... 17484bff34e3Sthurlow */ 17494bff34e3Sthurlow 17504bff34e3Sthurlow /* 17514bff34e3Sthurlow * NFS needs to go over the wire, just to be sure whether the 1752*02d09e03SGordon Ross * file exists or not. Using a cached result is dangerous in 17534bff34e3Sthurlow * this case when making a decision regarding existence. 17544bff34e3Sthurlow * 17554bff34e3Sthurlow * The SMB protocol does NOT really need to go OTW here 17564bff34e3Sthurlow * thanks to the expressive NTCREATE disposition values. 17574bff34e3Sthurlow * Unfortunately, to do Unix access checks correctly, 17584bff34e3Sthurlow * we need to know if the object already exists. 17594bff34e3Sthurlow * When the object does not exist, we need VWRITE on 17604bff34e3Sthurlow * the directory. Note: smbfslookup() checks VEXEC. 17614bff34e3Sthurlow */ 17624bff34e3Sthurlow error = smbfslookup(dvp, nm, &vp, cr, 0, ct); 17634bff34e3Sthurlow if (error == 0) { 17644bff34e3Sthurlow /* 176542645588SGordon Ross * The file already exists. Error? 176642645588SGordon Ross * NB: have a hold from smbfslookup 17674bff34e3Sthurlow */ 17684bff34e3Sthurlow if (exclusive == EXCL) { 17694bff34e3Sthurlow error = EEXIST; 177042645588SGordon Ross VN_RELE(vp); 17714bff34e3Sthurlow goto out; 17724bff34e3Sthurlow } 17734bff34e3Sthurlow /* 17744bff34e3Sthurlow * Verify requested access. 17754bff34e3Sthurlow */ 17764bff34e3Sthurlow error = smbfs_access(vp, mode, 0, cr, ct); 177742645588SGordon Ross if (error) { 177842645588SGordon Ross VN_RELE(vp); 17794bff34e3Sthurlow goto out; 178042645588SGordon Ross } 17814bff34e3Sthurlow 17824bff34e3Sthurlow /* 17834bff34e3Sthurlow * Truncate (if requested). 17844bff34e3Sthurlow */ 17854bff34e3Sthurlow if ((vattr.va_mask & AT_SIZE) && vattr.va_size == 0) { 17864bff34e3Sthurlow vattr.va_mask = AT_SIZE; 17874bff34e3Sthurlow error = smbfssetattr(vp, &vattr, 0, cr); 178842645588SGordon Ross if (error) { 178942645588SGordon Ross VN_RELE(vp); 17904bff34e3Sthurlow goto out; 179142645588SGordon Ross } 17924bff34e3Sthurlow } 17934bff34e3Sthurlow /* Success! */ 17944bff34e3Sthurlow #ifdef NOT_YET 17954bff34e3Sthurlow vnevent_create(vp, ct); 17964bff34e3Sthurlow #endif 17974bff34e3Sthurlow *vpp = vp; 17984bff34e3Sthurlow goto out; 17994bff34e3Sthurlow } 18004bff34e3Sthurlow 18014bff34e3Sthurlow /* 18024bff34e3Sthurlow * The file did not exist. Need VWRITE in the directory. 18034bff34e3Sthurlow */ 18044bff34e3Sthurlow error = smbfs_access(dvp, VWRITE, 0, cr, ct); 18054bff34e3Sthurlow if (error) 18064bff34e3Sthurlow goto out; 18074bff34e3Sthurlow 18084bff34e3Sthurlow /* 18094bff34e3Sthurlow * Now things get tricky. We also need to check the 18104bff34e3Sthurlow * requested open mode against the file we may create. 18114bff34e3Sthurlow * See comments at smbfs_access_rwx 18124bff34e3Sthurlow */ 18134bff34e3Sthurlow error = smbfs_access_rwx(vfsp, VREG, mode, cr); 18144bff34e3Sthurlow if (error) 18154bff34e3Sthurlow goto out; 18164bff34e3Sthurlow 18174bff34e3Sthurlow /* 18184bff34e3Sthurlow * Now the code derived from Darwin, 18194bff34e3Sthurlow * but with greater use of NT_CREATE 18204bff34e3Sthurlow * disposition options. Much changed. 18214bff34e3Sthurlow * 18224bff34e3Sthurlow * Create (or open) a new child node. 18234bff34e3Sthurlow * Note we handled "." and ".." above. 18244bff34e3Sthurlow */ 18254bff34e3Sthurlow 18264bff34e3Sthurlow if (exclusive == EXCL) 18274bff34e3Sthurlow disp = NTCREATEX_DISP_CREATE; 18284bff34e3Sthurlow else { 18294bff34e3Sthurlow /* Truncate regular files if requested. */ 18304bff34e3Sthurlow if ((va->va_type == VREG) && 18314bff34e3Sthurlow (va->va_mask & AT_SIZE) && 18324bff34e3Sthurlow (va->va_size == 0)) 18334bff34e3Sthurlow disp = NTCREATEX_DISP_OVERWRITE_IF; 18344bff34e3Sthurlow else 18354bff34e3Sthurlow disp = NTCREATEX_DISP_OPEN_IF; 18364bff34e3Sthurlow } 183791d632c8Sgwr xattr = (dnp->n_flag & N_XATTR) ? 1 : 0; 1838*02d09e03SGordon Ross error = smbfs_smb_create(dnp, 1839*02d09e03SGordon Ross name, nmlen, xattr, 1840*02d09e03SGordon Ross disp, &scred, &fid); 18414bff34e3Sthurlow if (error) 18424bff34e3Sthurlow goto out; 18434bff34e3Sthurlow 18444bff34e3Sthurlow /* 18454bff34e3Sthurlow * XXX: Missing some code here to deal with 18464bff34e3Sthurlow * the case where we opened an existing file, 18474bff34e3Sthurlow * it's size is larger than 32-bits, and we're 18484bff34e3Sthurlow * setting the size from a process that's not 18494bff34e3Sthurlow * aware of large file offsets. i.e. 18504bff34e3Sthurlow * from the NFS3 code: 18514bff34e3Sthurlow */ 18524bff34e3Sthurlow #if NOT_YET /* XXX */ 18534bff34e3Sthurlow if ((vattr.va_mask & AT_SIZE) && 18544bff34e3Sthurlow vp->v_type == VREG) { 18554bff34e3Sthurlow np = VTOSMB(vp); 18564bff34e3Sthurlow /* 18574bff34e3Sthurlow * Check here for large file handled 18584bff34e3Sthurlow * by LF-unaware process (as 18594bff34e3Sthurlow * ufs_create() does) 18604bff34e3Sthurlow */ 18614bff34e3Sthurlow if (!(lfaware & FOFFMAX)) { 18624bff34e3Sthurlow mutex_enter(&np->r_statelock); 18634bff34e3Sthurlow if (np->r_size > MAXOFF32_T) 18644bff34e3Sthurlow error = EOVERFLOW; 18654bff34e3Sthurlow mutex_exit(&np->r_statelock); 18664bff34e3Sthurlow } 18674bff34e3Sthurlow if (!error) { 18684bff34e3Sthurlow vattr.va_mask = AT_SIZE; 18694bff34e3Sthurlow error = smbfssetattr(vp, 18704bff34e3Sthurlow &vattr, 0, cr); 18714bff34e3Sthurlow } 18724bff34e3Sthurlow } 18734bff34e3Sthurlow #endif /* XXX */ 18744bff34e3Sthurlow /* 18754bff34e3Sthurlow * Should use the fid to get/set the size 18764bff34e3Sthurlow * while we have it opened here. See above. 18774bff34e3Sthurlow */ 18784bff34e3Sthurlow 18794bff34e3Sthurlow cerror = smbfs_smb_close(smi->smi_share, fid, NULL, &scred); 18804bff34e3Sthurlow if (cerror) 1881*02d09e03SGordon Ross SMBVDEBUG("error %d closing %s\\%s\n", 18824bff34e3Sthurlow cerror, dnp->n_rpath, name); 18834bff34e3Sthurlow 18844bff34e3Sthurlow /* 18854bff34e3Sthurlow * In the open case, the name may differ a little 18864bff34e3Sthurlow * from what we passed to create (case, etc.) 18874bff34e3Sthurlow * so call lookup to get the (opened) name. 18884bff34e3Sthurlow * 18894bff34e3Sthurlow * XXX: Could avoid this extra lookup if the 18904bff34e3Sthurlow * "createact" result from NT_CREATE says we 18914bff34e3Sthurlow * created the object. 18924bff34e3Sthurlow */ 18934bff34e3Sthurlow error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred); 18944bff34e3Sthurlow if (error) 18954bff34e3Sthurlow goto out; 18964bff34e3Sthurlow 18974bff34e3Sthurlow /* update attr and directory cache */ 18984bff34e3Sthurlow smbfs_attr_touchdir(dnp); 18994bff34e3Sthurlow 19004bff34e3Sthurlow error = smbfs_nget(dvp, name, nmlen, &fattr, &vp); 19014bff34e3Sthurlow if (error) 19024bff34e3Sthurlow goto out; 19034bff34e3Sthurlow 190491d632c8Sgwr /* XXX invalidate pages if we truncated? */ 190591d632c8Sgwr 19064bff34e3Sthurlow /* Success! */ 19074bff34e3Sthurlow *vpp = vp; 19084bff34e3Sthurlow error = 0; 19094bff34e3Sthurlow 19104bff34e3Sthurlow out: 19114bff34e3Sthurlow smb_credrele(&scred); 1912*02d09e03SGordon Ross smbfs_rw_exit(&dnp->r_rwlock); 19134bff34e3Sthurlow if (name != nm) 19144bff34e3Sthurlow smbfs_name_free(name, nmlen); 19154bff34e3Sthurlow return (error); 19164bff34e3Sthurlow } 19174bff34e3Sthurlow 19184bff34e3Sthurlow /* 19194bff34e3Sthurlow * XXX 19204bff34e3Sthurlow * This op should support the new FIGNORECASE flag for case-insensitive 19214bff34e3Sthurlow * lookups, per PSARC 2007/244. 19224bff34e3Sthurlow */ 19234bff34e3Sthurlow /* ARGSUSED */ 19244bff34e3Sthurlow static int 19254bff34e3Sthurlow smbfs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct, 19264bff34e3Sthurlow int flags) 19274bff34e3Sthurlow { 19284bff34e3Sthurlow int error; 19294bff34e3Sthurlow vnode_t *vp; 19304bff34e3Sthurlow smbnode_t *np; 19314bff34e3Sthurlow smbnode_t *dnp; 19324bff34e3Sthurlow struct smb_cred scred; 19334bff34e3Sthurlow /* enum smbfsstat status; */ 19344bff34e3Sthurlow smbmntinfo_t *smi; 19354bff34e3Sthurlow 19364bff34e3Sthurlow smi = VTOSMI(dvp); 19374bff34e3Sthurlow 19384bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 19394bff34e3Sthurlow return (EPERM); 19404bff34e3Sthurlow 19414bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 19424bff34e3Sthurlow return (EIO); 19434bff34e3Sthurlow 19444bff34e3Sthurlow dnp = VTOSMB(dvp); 19454bff34e3Sthurlow if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp))) 19464bff34e3Sthurlow return (EINTR); 1947*02d09e03SGordon Ross smb_credinit(&scred, cr); 19484bff34e3Sthurlow 19494bff34e3Sthurlow /* 19504bff34e3Sthurlow * Verify access to the dirctory. 19514bff34e3Sthurlow */ 19524bff34e3Sthurlow error = smbfs_access(dvp, VWRITE|VEXEC, 0, cr, ct); 19534bff34e3Sthurlow if (error) 19544bff34e3Sthurlow goto out; 19554bff34e3Sthurlow 19564bff34e3Sthurlow /* 19574bff34e3Sthurlow * NOTE: the darwin code gets the "vp" passed in so it looks 19584bff34e3Sthurlow * like the "vp" has probably been "lookup"ed by the VFS layer. 19594bff34e3Sthurlow * It looks like we will need to lookup the vp to check the 19604bff34e3Sthurlow * caches and check if the object being deleted is a directory. 19614bff34e3Sthurlow */ 19624bff34e3Sthurlow error = smbfslookup(dvp, nm, &vp, cr, 0, ct); 19634bff34e3Sthurlow if (error) 19644bff34e3Sthurlow goto out; 19654bff34e3Sthurlow 19664bff34e3Sthurlow /* Never allow link/unlink directories on CIFS. */ 19674bff34e3Sthurlow if (vp->v_type == VDIR) { 19684bff34e3Sthurlow VN_RELE(vp); 19694bff34e3Sthurlow error = EPERM; 19704bff34e3Sthurlow goto out; 19714bff34e3Sthurlow } 19724bff34e3Sthurlow 19734bff34e3Sthurlow /* 19744bff34e3Sthurlow * Now we have the real reference count on the vnode 1975*02d09e03SGordon Ross * Do we have the file open? 19764bff34e3Sthurlow */ 19774bff34e3Sthurlow np = VTOSMB(vp); 19784bff34e3Sthurlow mutex_enter(&np->r_statelock); 1979*02d09e03SGordon Ross if ((vp->v_count > 1) && (np->n_fidrefs > 0)) { 19804bff34e3Sthurlow /* 19814bff34e3Sthurlow * NFS does a rename on remove here. 19824bff34e3Sthurlow * Probably not applicable for SMB. 19834bff34e3Sthurlow * Like Darwin, just return EBUSY. 19844bff34e3Sthurlow * 1985*02d09e03SGordon Ross * XXX: Todo - Use Trans2rename, and 1986*02d09e03SGordon Ross * if that fails, ask the server to 19874bff34e3Sthurlow * set the delete-on-close flag. 19884bff34e3Sthurlow */ 19894bff34e3Sthurlow mutex_exit(&np->r_statelock); 19904bff34e3Sthurlow error = EBUSY; 19914bff34e3Sthurlow } else { 1992*02d09e03SGordon Ross smbfs_attrcache_rm_locked(np); 19934bff34e3Sthurlow mutex_exit(&np->r_statelock); 19944bff34e3Sthurlow 19954bff34e3Sthurlow error = smbfs_smb_delete(np, &scred, NULL, 0, 0); 19964bff34e3Sthurlow 1997*02d09e03SGordon Ross /* 1998*02d09e03SGordon Ross * If the file should no longer exist, discard 1999*02d09e03SGordon Ross * any cached attributes under this node. 2000*02d09e03SGordon Ross */ 2001*02d09e03SGordon Ross switch (error) { 2002*02d09e03SGordon Ross case 0: 2003*02d09e03SGordon Ross case ENOENT: 2004*02d09e03SGordon Ross case ENOTDIR: 2005*02d09e03SGordon Ross smbfs_attrcache_prune(np); 2006*02d09e03SGordon Ross break; 2007*02d09e03SGordon Ross } 20084bff34e3Sthurlow } 20094bff34e3Sthurlow 20104bff34e3Sthurlow VN_RELE(vp); 20114bff34e3Sthurlow 20124bff34e3Sthurlow out: 2013*02d09e03SGordon Ross smb_credrele(&scred); 20144bff34e3Sthurlow smbfs_rw_exit(&dnp->r_rwlock); 20154bff34e3Sthurlow 20164bff34e3Sthurlow return (error); 20174bff34e3Sthurlow } 20184bff34e3Sthurlow 20194bff34e3Sthurlow 20204bff34e3Sthurlow /* 20214bff34e3Sthurlow * XXX 20224bff34e3Sthurlow * This op should support the new FIGNORECASE flag for case-insensitive 20234bff34e3Sthurlow * lookups, per PSARC 2007/244. 20244bff34e3Sthurlow */ 20254bff34e3Sthurlow /* ARGSUSED */ 20264bff34e3Sthurlow static int 20274bff34e3Sthurlow smbfs_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr, 20284bff34e3Sthurlow caller_context_t *ct, int flags) 20294bff34e3Sthurlow { 20304bff34e3Sthurlow /* vnode_t *realvp; */ 20314bff34e3Sthurlow 20324bff34e3Sthurlow if (curproc->p_zone != VTOSMI(odvp)->smi_zone || 20334bff34e3Sthurlow curproc->p_zone != VTOSMI(ndvp)->smi_zone) 20344bff34e3Sthurlow return (EPERM); 20354bff34e3Sthurlow 20364bff34e3Sthurlow if (VTOSMI(odvp)->smi_flags & SMI_DEAD || 20374bff34e3Sthurlow VTOSMI(ndvp)->smi_flags & SMI_DEAD || 20384bff34e3Sthurlow odvp->v_vfsp->vfs_flag & VFS_UNMOUNTED || 20394bff34e3Sthurlow ndvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 20404bff34e3Sthurlow return (EIO); 20414bff34e3Sthurlow 20424bff34e3Sthurlow return (smbfsrename(odvp, onm, ndvp, nnm, cr, ct)); 20434bff34e3Sthurlow } 20444bff34e3Sthurlow 20454bff34e3Sthurlow /* 20464bff34e3Sthurlow * smbfsrename does the real work of renaming in SMBFS 20474bff34e3Sthurlow */ 20484bff34e3Sthurlow /* ARGSUSED */ 20494bff34e3Sthurlow static int 20504bff34e3Sthurlow smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr, 20514bff34e3Sthurlow caller_context_t *ct) 20524bff34e3Sthurlow { 20534bff34e3Sthurlow int error; 20544bff34e3Sthurlow int nvp_locked = 0; 20554bff34e3Sthurlow vnode_t *nvp = NULL; 20564bff34e3Sthurlow vnode_t *ovp = NULL; 20574bff34e3Sthurlow smbnode_t *onp; 205891d632c8Sgwr smbnode_t *nnp; 20594bff34e3Sthurlow smbnode_t *odnp; 20604bff34e3Sthurlow smbnode_t *ndnp; 20614bff34e3Sthurlow struct smb_cred scred; 20624bff34e3Sthurlow /* enum smbfsstat status; */ 20634bff34e3Sthurlow 20644bff34e3Sthurlow ASSERT(curproc->p_zone == VTOSMI(odvp)->smi_zone); 20654bff34e3Sthurlow 20664bff34e3Sthurlow if (strcmp(onm, ".") == 0 || strcmp(onm, "..") == 0 || 20674bff34e3Sthurlow strcmp(nnm, ".") == 0 || strcmp(nnm, "..") == 0) 20684bff34e3Sthurlow return (EINVAL); 20694bff34e3Sthurlow 20704bff34e3Sthurlow /* 20714bff34e3Sthurlow * Check that everything is on the same filesystem. 20724bff34e3Sthurlow * vn_rename checks the fsid's, but in case we don't 20734bff34e3Sthurlow * fill those in correctly, check here too. 20744bff34e3Sthurlow */ 20754bff34e3Sthurlow if (odvp->v_vfsp != ndvp->v_vfsp) 20764bff34e3Sthurlow return (EXDEV); 20774bff34e3Sthurlow 20784bff34e3Sthurlow odnp = VTOSMB(odvp); 20794bff34e3Sthurlow ndnp = VTOSMB(ndvp); 20804bff34e3Sthurlow 20814bff34e3Sthurlow /* 20824bff34e3Sthurlow * Avoid deadlock here on old vs new directory nodes 20834bff34e3Sthurlow * by always taking the locks in order of address. 20844bff34e3Sthurlow * The order is arbitrary, but must be consistent. 20854bff34e3Sthurlow */ 20864bff34e3Sthurlow if (odnp < ndnp) { 20874bff34e3Sthurlow if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER, 20884bff34e3Sthurlow SMBINTR(odvp))) 20894bff34e3Sthurlow return (EINTR); 20904bff34e3Sthurlow if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER, 20914bff34e3Sthurlow SMBINTR(ndvp))) { 20924bff34e3Sthurlow smbfs_rw_exit(&odnp->r_rwlock); 20934bff34e3Sthurlow return (EINTR); 20944bff34e3Sthurlow } 20954bff34e3Sthurlow } else { 20964bff34e3Sthurlow if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER, 20974bff34e3Sthurlow SMBINTR(ndvp))) 20984bff34e3Sthurlow return (EINTR); 20994bff34e3Sthurlow if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER, 21004bff34e3Sthurlow SMBINTR(odvp))) { 21014bff34e3Sthurlow smbfs_rw_exit(&ndnp->r_rwlock); 21024bff34e3Sthurlow return (EINTR); 21034bff34e3Sthurlow } 21044bff34e3Sthurlow } 2105*02d09e03SGordon Ross smb_credinit(&scred, cr); 21064bff34e3Sthurlow /* 21074bff34e3Sthurlow * No returns after this point (goto out) 21084bff34e3Sthurlow */ 21094bff34e3Sthurlow 21104bff34e3Sthurlow /* 21114bff34e3Sthurlow * Need write access on source and target. 21124bff34e3Sthurlow * Server takes care of most checks. 21134bff34e3Sthurlow */ 21144bff34e3Sthurlow error = smbfs_access(odvp, VWRITE|VEXEC, 0, cr, ct); 21154bff34e3Sthurlow if (error) 21164bff34e3Sthurlow goto out; 21174bff34e3Sthurlow if (odvp != ndvp) { 21184bff34e3Sthurlow error = smbfs_access(ndvp, VWRITE, 0, cr, ct); 21194bff34e3Sthurlow if (error) 21204bff34e3Sthurlow goto out; 21214bff34e3Sthurlow } 21224bff34e3Sthurlow 21234bff34e3Sthurlow /* 21244bff34e3Sthurlow * Lookup the source name. Must already exist. 21254bff34e3Sthurlow */ 21264bff34e3Sthurlow error = smbfslookup(odvp, onm, &ovp, cr, 0, ct); 21274bff34e3Sthurlow if (error) 21284bff34e3Sthurlow goto out; 21294bff34e3Sthurlow 21304bff34e3Sthurlow /* 21314bff34e3Sthurlow * Lookup the target file. If it exists, it needs to be 21324bff34e3Sthurlow * checked to see whether it is a mount point and whether 21334bff34e3Sthurlow * it is active (open). 21344bff34e3Sthurlow */ 21354bff34e3Sthurlow error = smbfslookup(ndvp, nnm, &nvp, cr, 0, ct); 21364bff34e3Sthurlow if (!error) { 21374bff34e3Sthurlow /* 21384bff34e3Sthurlow * Target (nvp) already exists. Check that it 21394bff34e3Sthurlow * has the same type as the source. The server 21404bff34e3Sthurlow * will check this also, (and more reliably) but 21414bff34e3Sthurlow * this lets us return the correct error codes. 21424bff34e3Sthurlow */ 21434bff34e3Sthurlow if (ovp->v_type == VDIR) { 21444bff34e3Sthurlow if (nvp->v_type != VDIR) { 21454bff34e3Sthurlow error = ENOTDIR; 21464bff34e3Sthurlow goto out; 21474bff34e3Sthurlow } 21484bff34e3Sthurlow } else { 21494bff34e3Sthurlow if (nvp->v_type == VDIR) { 21504bff34e3Sthurlow error = EISDIR; 21514bff34e3Sthurlow goto out; 21524bff34e3Sthurlow } 21534bff34e3Sthurlow } 21544bff34e3Sthurlow 21554bff34e3Sthurlow /* 21564bff34e3Sthurlow * POSIX dictates that when the source and target 21574bff34e3Sthurlow * entries refer to the same file object, rename 21584bff34e3Sthurlow * must do nothing and exit without error. 21594bff34e3Sthurlow */ 21604bff34e3Sthurlow if (ovp == nvp) { 21614bff34e3Sthurlow error = 0; 21624bff34e3Sthurlow goto out; 21634bff34e3Sthurlow } 21644bff34e3Sthurlow 21654bff34e3Sthurlow /* 21664bff34e3Sthurlow * Also must ensure the target is not a mount point, 21674bff34e3Sthurlow * and keep mount/umount away until we're done. 21684bff34e3Sthurlow */ 21694bff34e3Sthurlow if (vn_vfsrlock(nvp)) { 21704bff34e3Sthurlow error = EBUSY; 21714bff34e3Sthurlow goto out; 21724bff34e3Sthurlow } 21734bff34e3Sthurlow nvp_locked = 1; 21744bff34e3Sthurlow if (vn_mountedvfs(nvp) != NULL) { 21754bff34e3Sthurlow error = EBUSY; 21764bff34e3Sthurlow goto out; 21774bff34e3Sthurlow } 21784bff34e3Sthurlow 217991d632c8Sgwr /* 218091d632c8Sgwr * CIFS gives a SHARING_VIOLATION error when 218191d632c8Sgwr * trying to rename onto an exising object, 218291d632c8Sgwr * so try to remove the target first. 218391d632c8Sgwr * (Only for files, not directories.) 218491d632c8Sgwr */ 218591d632c8Sgwr if (nvp->v_type == VDIR) { 218691d632c8Sgwr error = EEXIST; 218791d632c8Sgwr goto out; 218891d632c8Sgwr } 21894bff34e3Sthurlow 219091d632c8Sgwr /* 219142645588SGordon Ross * Nodes that are "not active" here have v_count=2 219242645588SGordon Ross * because vn_renameat (our caller) did a lookup on 219342645588SGordon Ross * both the source and target before this call. 219442645588SGordon Ross * Otherwise this similar to smbfs_remove. 219591d632c8Sgwr */ 219691d632c8Sgwr nnp = VTOSMB(nvp); 219791d632c8Sgwr mutex_enter(&nnp->r_statelock); 2198*02d09e03SGordon Ross if ((nvp->v_count > 2) && (nnp->n_fidrefs > 0)) { 21994bff34e3Sthurlow /* 22004bff34e3Sthurlow * The target file exists, is not the same as 22014bff34e3Sthurlow * the source file, and is active. Other FS 22024bff34e3Sthurlow * implementations unlink the target here. 22034bff34e3Sthurlow * For SMB, we don't assume we can remove an 22044bff34e3Sthurlow * open file. Return an error instead. 22054bff34e3Sthurlow */ 220691d632c8Sgwr mutex_exit(&nnp->r_statelock); 220791d632c8Sgwr error = EBUSY; 22084bff34e3Sthurlow goto out; 22094bff34e3Sthurlow } 221091d632c8Sgwr 221191d632c8Sgwr /* 221291d632c8Sgwr * Target file is not active. Try to remove it. 221391d632c8Sgwr */ 2214*02d09e03SGordon Ross smbfs_attrcache_rm_locked(nnp); 2215*02d09e03SGordon Ross mutex_exit(&nnp->r_statelock); 2216*02d09e03SGordon Ross 221791d632c8Sgwr error = smbfs_smb_delete(nnp, &scred, NULL, 0, 0); 2218*02d09e03SGordon Ross 2219*02d09e03SGordon Ross /* 2220*02d09e03SGordon Ross * Similar to smbfs_remove 2221*02d09e03SGordon Ross */ 2222*02d09e03SGordon Ross switch (error) { 2223*02d09e03SGordon Ross case 0: 2224*02d09e03SGordon Ross case ENOENT: 2225*02d09e03SGordon Ross case ENOTDIR: 2226*02d09e03SGordon Ross smbfs_attrcache_prune(nnp); 2227*02d09e03SGordon Ross break; 2228*02d09e03SGordon Ross } 2229*02d09e03SGordon Ross 223091d632c8Sgwr if (error) 223191d632c8Sgwr goto out; 223291d632c8Sgwr /* 223391d632c8Sgwr * OK, removed the target file. Continue as if 223491d632c8Sgwr * lookup target had failed (nvp == NULL). 223591d632c8Sgwr */ 223691d632c8Sgwr vn_vfsunlock(nvp); 223791d632c8Sgwr nvp_locked = 0; 223891d632c8Sgwr VN_RELE(nvp); 223991d632c8Sgwr nvp = NULL; 22404bff34e3Sthurlow } /* nvp */ 22414bff34e3Sthurlow 22424bff34e3Sthurlow onp = VTOSMB(ovp); 2243*02d09e03SGordon Ross smbfs_attrcache_remove(onp); 2244*02d09e03SGordon Ross 22454bff34e3Sthurlow error = smbfs_smb_rename(onp, ndnp, nnm, strlen(nnm), &scred); 22464bff34e3Sthurlow 2247*02d09e03SGordon Ross /* 2248*02d09e03SGordon Ross * If the old name should no longer exist, 2249*02d09e03SGordon Ross * discard any cached attributes under it. 2250*02d09e03SGordon Ross */ 2251*02d09e03SGordon Ross if (error == 0) 2252*02d09e03SGordon Ross smbfs_attrcache_prune(onp); 22534bff34e3Sthurlow 22544bff34e3Sthurlow out: 22554bff34e3Sthurlow if (nvp) { 22564bff34e3Sthurlow if (nvp_locked) 22574bff34e3Sthurlow vn_vfsunlock(nvp); 22584bff34e3Sthurlow VN_RELE(nvp); 22594bff34e3Sthurlow } 22604bff34e3Sthurlow if (ovp) 22614bff34e3Sthurlow VN_RELE(ovp); 22624bff34e3Sthurlow 2263*02d09e03SGordon Ross smb_credrele(&scred); 22644bff34e3Sthurlow smbfs_rw_exit(&odnp->r_rwlock); 22654bff34e3Sthurlow smbfs_rw_exit(&ndnp->r_rwlock); 22664bff34e3Sthurlow 22674bff34e3Sthurlow return (error); 22684bff34e3Sthurlow } 22694bff34e3Sthurlow 22704bff34e3Sthurlow /* 22714bff34e3Sthurlow * XXX 22724bff34e3Sthurlow * vsecattr_t is new to build 77, and we need to eventually support 22734bff34e3Sthurlow * it in order to create an ACL when an object is created. 22744bff34e3Sthurlow * 22754bff34e3Sthurlow * This op should support the new FIGNORECASE flag for case-insensitive 22764bff34e3Sthurlow * lookups, per PSARC 2007/244. 22774bff34e3Sthurlow */ 22784bff34e3Sthurlow /* ARGSUSED */ 22794bff34e3Sthurlow static int 22804bff34e3Sthurlow smbfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp, 22814bff34e3Sthurlow cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp) 22824bff34e3Sthurlow { 22834bff34e3Sthurlow vnode_t *vp; 22844bff34e3Sthurlow struct smbnode *dnp = VTOSMB(dvp); 22854bff34e3Sthurlow struct smbmntinfo *smi = VTOSMI(dvp); 22864bff34e3Sthurlow struct smb_cred scred; 22874bff34e3Sthurlow struct smbfattr fattr; 22884bff34e3Sthurlow const char *name = (const char *) nm; 22894bff34e3Sthurlow int nmlen = strlen(name); 22904bff34e3Sthurlow int error, hiderr; 22914bff34e3Sthurlow 22924bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 22934bff34e3Sthurlow return (EPERM); 22944bff34e3Sthurlow 22954bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 22964bff34e3Sthurlow return (EIO); 22974bff34e3Sthurlow 22984bff34e3Sthurlow if ((nmlen == 1 && name[0] == '.') || 22994bff34e3Sthurlow (nmlen == 2 && name[0] == '.' && name[1] == '.')) 23004bff34e3Sthurlow return (EEXIST); 23014bff34e3Sthurlow 230291d632c8Sgwr /* Only plain files are allowed in V_XATTRDIR. */ 230391d632c8Sgwr if (dvp->v_flag & V_XATTRDIR) 230491d632c8Sgwr return (EINVAL); 230591d632c8Sgwr 23064bff34e3Sthurlow if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp))) 23074bff34e3Sthurlow return (EINTR); 2308613a2f6bSGordon Ross smb_credinit(&scred, cr); 23094bff34e3Sthurlow 23104bff34e3Sthurlow /* 23114bff34e3Sthurlow * XXX: Do we need r_lkserlock too? 23124bff34e3Sthurlow * No use of any shared fid or fctx... 23134bff34e3Sthurlow */ 23144bff34e3Sthurlow 23154bff34e3Sthurlow /* 23164bff34e3Sthurlow * Require write access in the containing directory. 23174bff34e3Sthurlow */ 23184bff34e3Sthurlow error = smbfs_access(dvp, VWRITE, 0, cr, ct); 23194bff34e3Sthurlow if (error) 23204bff34e3Sthurlow goto out; 23214bff34e3Sthurlow 23224bff34e3Sthurlow error = smbfs_smb_mkdir(dnp, name, nmlen, &scred); 23234bff34e3Sthurlow if (error) 23244bff34e3Sthurlow goto out; 23254bff34e3Sthurlow 23264bff34e3Sthurlow error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred); 23274bff34e3Sthurlow if (error) 23284bff34e3Sthurlow goto out; 23294bff34e3Sthurlow 23304bff34e3Sthurlow smbfs_attr_touchdir(dnp); 23314bff34e3Sthurlow 23324bff34e3Sthurlow error = smbfs_nget(dvp, name, nmlen, &fattr, &vp); 23334bff34e3Sthurlow if (error) 23344bff34e3Sthurlow goto out; 23354bff34e3Sthurlow 23364bff34e3Sthurlow if (name[0] == '.') 23374bff34e3Sthurlow if ((hiderr = smbfs_smb_hideit(VTOSMB(vp), NULL, 0, &scred))) 23384bff34e3Sthurlow SMBVDEBUG("hide failure %d\n", hiderr); 23394bff34e3Sthurlow 23404bff34e3Sthurlow /* Success! */ 23414bff34e3Sthurlow *vpp = vp; 23424bff34e3Sthurlow error = 0; 23434bff34e3Sthurlow out: 23444bff34e3Sthurlow smb_credrele(&scred); 23454bff34e3Sthurlow smbfs_rw_exit(&dnp->r_rwlock); 23464bff34e3Sthurlow 23474bff34e3Sthurlow if (name != nm) 23484bff34e3Sthurlow smbfs_name_free(name, nmlen); 23494bff34e3Sthurlow 23504bff34e3Sthurlow return (error); 23514bff34e3Sthurlow } 23524bff34e3Sthurlow 23534bff34e3Sthurlow /* 23544bff34e3Sthurlow * XXX 23554bff34e3Sthurlow * This op should support the new FIGNORECASE flag for case-insensitive 23564bff34e3Sthurlow * lookups, per PSARC 2007/244. 23574bff34e3Sthurlow */ 23584bff34e3Sthurlow /* ARGSUSED */ 23594bff34e3Sthurlow static int 23604bff34e3Sthurlow smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr, 23614bff34e3Sthurlow caller_context_t *ct, int flags) 23624bff34e3Sthurlow { 23634bff34e3Sthurlow vnode_t *vp = NULL; 23644bff34e3Sthurlow int vp_locked = 0; 23654bff34e3Sthurlow struct smbmntinfo *smi = VTOSMI(dvp); 23664bff34e3Sthurlow struct smbnode *dnp = VTOSMB(dvp); 23674bff34e3Sthurlow struct smbnode *np; 23684bff34e3Sthurlow struct smb_cred scred; 23694bff34e3Sthurlow int error; 23704bff34e3Sthurlow 23714bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 23724bff34e3Sthurlow return (EPERM); 23734bff34e3Sthurlow 23744bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 23754bff34e3Sthurlow return (EIO); 23764bff34e3Sthurlow 23774bff34e3Sthurlow if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp))) 23784bff34e3Sthurlow return (EINTR); 2379613a2f6bSGordon Ross smb_credinit(&scred, cr); 23804bff34e3Sthurlow 23814bff34e3Sthurlow /* 23824bff34e3Sthurlow * Require w/x access in the containing directory. 23834bff34e3Sthurlow * Server handles all other access checks. 23844bff34e3Sthurlow */ 23854bff34e3Sthurlow error = smbfs_access(dvp, VEXEC|VWRITE, 0, cr, ct); 23864bff34e3Sthurlow if (error) 23874bff34e3Sthurlow goto out; 23884bff34e3Sthurlow 23894bff34e3Sthurlow /* 23904bff34e3Sthurlow * First lookup the entry to be removed. 23914bff34e3Sthurlow */ 23924bff34e3Sthurlow error = smbfslookup(dvp, nm, &vp, cr, 0, ct); 23934bff34e3Sthurlow if (error) 23944bff34e3Sthurlow goto out; 23954bff34e3Sthurlow np = VTOSMB(vp); 23964bff34e3Sthurlow 23974bff34e3Sthurlow /* 23984bff34e3Sthurlow * Disallow rmdir of "." or current dir, or the FS root. 23994bff34e3Sthurlow * Also make sure it's a directory, not a mount point, 24004bff34e3Sthurlow * and lock to keep mount/umount away until we're done. 24014bff34e3Sthurlow */ 24024bff34e3Sthurlow if ((vp == dvp) || (vp == cdir) || (vp->v_flag & VROOT)) { 24034bff34e3Sthurlow error = EINVAL; 24044bff34e3Sthurlow goto out; 24054bff34e3Sthurlow } 24064bff34e3Sthurlow if (vp->v_type != VDIR) { 24074bff34e3Sthurlow error = ENOTDIR; 24084bff34e3Sthurlow goto out; 24094bff34e3Sthurlow } 24104bff34e3Sthurlow if (vn_vfsrlock(vp)) { 24114bff34e3Sthurlow error = EBUSY; 24124bff34e3Sthurlow goto out; 24134bff34e3Sthurlow } 24144bff34e3Sthurlow vp_locked = 1; 24154bff34e3Sthurlow if (vn_mountedvfs(vp) != NULL) { 24164bff34e3Sthurlow error = EBUSY; 24174bff34e3Sthurlow goto out; 24184bff34e3Sthurlow } 24194bff34e3Sthurlow 2420*02d09e03SGordon Ross smbfs_attrcache_remove(np); 2421*02d09e03SGordon Ross error = smbfs_smb_rmdir(np, &scred); 242291d632c8Sgwr 242391d632c8Sgwr /* 2424*02d09e03SGordon Ross * Similar to smbfs_remove 242591d632c8Sgwr */ 2426*02d09e03SGordon Ross switch (error) { 2427*02d09e03SGordon Ross case 0: 2428*02d09e03SGordon Ross case ENOENT: 2429*02d09e03SGordon Ross case ENOTDIR: 2430*02d09e03SGordon Ross smbfs_attrcache_prune(np); 2431*02d09e03SGordon Ross break; 243291d632c8Sgwr } 243391d632c8Sgwr 24344bff34e3Sthurlow if (error) 24354bff34e3Sthurlow goto out; 24364bff34e3Sthurlow 24374bff34e3Sthurlow mutex_enter(&np->r_statelock); 24384bff34e3Sthurlow dnp->n_flag |= NMODIFIED; 24394bff34e3Sthurlow mutex_exit(&np->r_statelock); 24404bff34e3Sthurlow smbfs_attr_touchdir(dnp); 2441*02d09e03SGordon Ross smbfs_rmhash(np); 24424bff34e3Sthurlow 24434bff34e3Sthurlow out: 24444bff34e3Sthurlow if (vp) { 24454bff34e3Sthurlow if (vp_locked) 24464bff34e3Sthurlow vn_vfsunlock(vp); 24474bff34e3Sthurlow VN_RELE(vp); 24484bff34e3Sthurlow } 24494bff34e3Sthurlow smb_credrele(&scred); 24504bff34e3Sthurlow smbfs_rw_exit(&dnp->r_rwlock); 24514bff34e3Sthurlow 24524bff34e3Sthurlow return (error); 24534bff34e3Sthurlow } 24544bff34e3Sthurlow 24554bff34e3Sthurlow 24564bff34e3Sthurlow /* ARGSUSED */ 24574bff34e3Sthurlow static int 24584bff34e3Sthurlow smbfs_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp, 24594bff34e3Sthurlow caller_context_t *ct, int flags) 24604bff34e3Sthurlow { 24614bff34e3Sthurlow struct smbnode *np = VTOSMB(vp); 24624bff34e3Sthurlow int error = 0; 24634bff34e3Sthurlow smbmntinfo_t *smi; 24644bff34e3Sthurlow 24654bff34e3Sthurlow smi = VTOSMI(vp); 24664bff34e3Sthurlow 24674bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 24684bff34e3Sthurlow return (EIO); 24694bff34e3Sthurlow 24704bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 24714bff34e3Sthurlow return (EIO); 24724bff34e3Sthurlow 24734bff34e3Sthurlow /* 24744bff34e3Sthurlow * Require read access in the directory. 24754bff34e3Sthurlow */ 24764bff34e3Sthurlow error = smbfs_access(vp, VREAD, 0, cr, ct); 24774bff34e3Sthurlow if (error) 24784bff34e3Sthurlow return (error); 24794bff34e3Sthurlow 24804bff34e3Sthurlow ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER)); 24814bff34e3Sthurlow 24824bff34e3Sthurlow /* 24834bff34e3Sthurlow * XXX: Todo readdir cache here 24844bff34e3Sthurlow * Note: NFS code is just below this. 24854bff34e3Sthurlow * 24864bff34e3Sthurlow * I am serializing the entire readdir opreation 24874bff34e3Sthurlow * now since we have not yet implemented readdir 24884bff34e3Sthurlow * cache. This fix needs to be revisited once 24894bff34e3Sthurlow * we implement readdir cache. 24904bff34e3Sthurlow */ 24914bff34e3Sthurlow if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp))) 24924bff34e3Sthurlow return (EINTR); 24934bff34e3Sthurlow 24944bff34e3Sthurlow error = smbfs_readvdir(vp, uiop, cr, eofp, ct); 24954bff34e3Sthurlow 24964bff34e3Sthurlow smbfs_rw_exit(&np->r_lkserlock); 24974bff34e3Sthurlow 24984bff34e3Sthurlow return (error); 24994bff34e3Sthurlow } 25004bff34e3Sthurlow 25014bff34e3Sthurlow /* ARGSUSED */ 25024bff34e3Sthurlow static int 25034bff34e3Sthurlow smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp, 25044bff34e3Sthurlow caller_context_t *ct) 25054bff34e3Sthurlow { 25065ecede33SGordon Ross /* 25075ecede33SGordon Ross * Note: "limit" tells the SMB-level FindFirst/FindNext 25085ecede33SGordon Ross * functions how many directory entries to request in 25095ecede33SGordon Ross * each OtW call. It needs to be large enough so that 25105ecede33SGordon Ross * we don't make lots of tiny OtW requests, but there's 25115ecede33SGordon Ross * no point making it larger than the maximum number of 25125ecede33SGordon Ross * OtW entries that would fit in a maximum sized trans2 25135ecede33SGordon Ross * response (64k / 48). Beyond that, it's just tuning. 25145ecede33SGordon Ross * WinNT used 512, Win2k used 1366. We use 1000. 25155ecede33SGordon Ross */ 25165ecede33SGordon Ross static const int limit = 1000; 25175ecede33SGordon Ross /* Largest possible dirent size. */ 25185ecede33SGordon Ross static const size_t dbufsiz = DIRENT64_RECLEN(SMB_MAXFNAMELEN); 25194bff34e3Sthurlow struct smb_cred scred; 25204bff34e3Sthurlow vnode_t *newvp; 25214bff34e3Sthurlow struct smbnode *np = VTOSMB(vp); 25224bff34e3Sthurlow struct smbfs_fctx *ctx; 25235ecede33SGordon Ross struct dirent64 *dp; 25245ecede33SGordon Ross ssize_t save_resid; 25255ecede33SGordon Ross offset_t save_offset; /* 64 bits */ 25265ecede33SGordon Ross int offset; /* yes, 32 bits */ 25275ecede33SGordon Ross int nmlen, error; 25285ecede33SGordon Ross ushort_t reclen; 25294bff34e3Sthurlow 25304bff34e3Sthurlow ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone); 25314bff34e3Sthurlow 25324bff34e3Sthurlow /* Make sure we serialize for n_dirseq use. */ 25334bff34e3Sthurlow ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_WRITER)); 25344bff34e3Sthurlow 25355ecede33SGordon Ross /* 25365ecede33SGordon Ross * Make sure smbfs_open filled in n_dirseq 25375ecede33SGordon Ross */ 25385ecede33SGordon Ross if (np->n_dirseq == NULL) 25395ecede33SGordon Ross return (EBADF); 25405ecede33SGordon Ross 25415ecede33SGordon Ross /* Check for overflow of (32-bit) directory offset. */ 25425ecede33SGordon Ross if (uio->uio_loffset < 0 || uio->uio_loffset > INT32_MAX || 25435ecede33SGordon Ross (uio->uio_loffset + uio->uio_resid) > INT32_MAX) 25445ecede33SGordon Ross return (EINVAL); 25455ecede33SGordon Ross 25465ecede33SGordon Ross /* Require space for at least one dirent. */ 25475ecede33SGordon Ross if (uio->uio_resid < dbufsiz) 25484bff34e3Sthurlow return (EINVAL); 25494bff34e3Sthurlow 25504bff34e3Sthurlow SMBVDEBUG("dirname='%s'\n", np->n_rpath); 2551613a2f6bSGordon Ross smb_credinit(&scred, cr); 25524bff34e3Sthurlow dp = kmem_alloc(dbufsiz, KM_SLEEP); 25534bff34e3Sthurlow 25545ecede33SGordon Ross save_resid = uio->uio_resid; 25555ecede33SGordon Ross save_offset = uio->uio_loffset; 25565ecede33SGordon Ross offset = uio->uio_offset; 25575ecede33SGordon Ross SMBVDEBUG("in: offset=%d, resid=%d\n", 25585ecede33SGordon Ross (int)uio->uio_offset, (int)uio->uio_resid); 25595ecede33SGordon Ross error = 0; 25604bff34e3Sthurlow 25614bff34e3Sthurlow /* 25624bff34e3Sthurlow * Generate the "." and ".." entries here so we can 25634bff34e3Sthurlow * (1) make sure they appear (but only once), and 25644bff34e3Sthurlow * (2) deal with getting their I numbers which the 25654bff34e3Sthurlow * findnext below does only for normal names. 25664bff34e3Sthurlow */ 25675ecede33SGordon Ross while (offset < FIRST_DIROFS) { 25685ecede33SGordon Ross /* 25695ecede33SGordon Ross * Tricky bit filling in the first two: 25705ecede33SGordon Ross * offset 0 is ".", offset 1 is ".." 25715ecede33SGordon Ross * so strlen of these is offset+1. 25725ecede33SGordon Ross */ 25734bff34e3Sthurlow reclen = DIRENT64_RECLEN(offset + 1); 25745ecede33SGordon Ross if (uio->uio_resid < reclen) 25755ecede33SGordon Ross goto out; 25764bff34e3Sthurlow bzero(dp, reclen); 25774bff34e3Sthurlow dp->d_reclen = reclen; 25784bff34e3Sthurlow dp->d_name[0] = '.'; 25794bff34e3Sthurlow dp->d_name[1] = '.'; 25804bff34e3Sthurlow dp->d_name[offset + 1] = '\0'; 25814bff34e3Sthurlow /* 25824bff34e3Sthurlow * Want the real I-numbers for the "." and ".." 25834bff34e3Sthurlow * entries. For these two names, we know that 25845ecede33SGordon Ross * smbfslookup can get the nodes efficiently. 25854bff34e3Sthurlow */ 25864bff34e3Sthurlow error = smbfslookup(vp, dp->d_name, &newvp, cr, 1, ct); 25874bff34e3Sthurlow if (error) { 25884bff34e3Sthurlow dp->d_ino = np->n_ino + offset; /* fiction */ 25894bff34e3Sthurlow } else { 25904bff34e3Sthurlow dp->d_ino = VTOSMB(newvp)->n_ino; 25914bff34e3Sthurlow VN_RELE(newvp); 25924bff34e3Sthurlow } 25935ecede33SGordon Ross /* 25945ecede33SGordon Ross * Note: d_off is the offset that a user-level program 25955ecede33SGordon Ross * should seek to for reading the NEXT directory entry. 25965ecede33SGordon Ross * See libc: readdir, telldir, seekdir 25975ecede33SGordon Ross */ 25985ecede33SGordon Ross dp->d_off = offset + 1; 25995ecede33SGordon Ross error = uiomove(dp, reclen, UIO_READ, uio); 26004bff34e3Sthurlow if (error) 26014bff34e3Sthurlow goto out; 26025ecede33SGordon Ross /* 26035ecede33SGordon Ross * Note: uiomove updates uio->uio_offset, 26045ecede33SGordon Ross * but we want it to be our "cookie" value, 26055ecede33SGordon Ross * which just counts dirents ignoring size. 26065ecede33SGordon Ross */ 26074bff34e3Sthurlow uio->uio_offset = ++offset; 26084bff34e3Sthurlow } 26095ecede33SGordon Ross 26105ecede33SGordon Ross /* 26115ecede33SGordon Ross * If there was a backward seek, we have to reopen. 26125ecede33SGordon Ross */ 26135ecede33SGordon Ross if (offset < np->n_dirofs) { 26145ecede33SGordon Ross SMBVDEBUG("Reopening search %d:%d\n", 26155ecede33SGordon Ross offset, np->n_dirofs); 26164bff34e3Sthurlow error = smbfs_smb_findopen(np, "*", 1, 26174bff34e3Sthurlow SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, 26184bff34e3Sthurlow &scred, &ctx); 26194bff34e3Sthurlow if (error) { 26204bff34e3Sthurlow SMBVDEBUG("can not open search, error = %d", error); 26214bff34e3Sthurlow goto out; 26224bff34e3Sthurlow } 26235ecede33SGordon Ross /* free the old one */ 26245ecede33SGordon Ross (void) smbfs_smb_findclose(np->n_dirseq, &scred); 26255ecede33SGordon Ross /* save the new one */ 26264bff34e3Sthurlow np->n_dirseq = ctx; 26275ecede33SGordon Ross np->n_dirofs = FIRST_DIROFS; 26285ecede33SGordon Ross } else { 26294bff34e3Sthurlow ctx = np->n_dirseq; 26305ecede33SGordon Ross } 26315ecede33SGordon Ross 26325ecede33SGordon Ross /* 26335ecede33SGordon Ross * Skip entries before the requested offset. 26345ecede33SGordon Ross */ 26354bff34e3Sthurlow while (np->n_dirofs < offset) { 26365ecede33SGordon Ross error = smbfs_smb_findnext(ctx, limit, &scred); 26375ecede33SGordon Ross if (error != 0) 26384bff34e3Sthurlow goto out; 26395ecede33SGordon Ross np->n_dirofs++; 26404bff34e3Sthurlow } 26415ecede33SGordon Ross 26425ecede33SGordon Ross /* 26435ecede33SGordon Ross * While there's room in the caller's buffer: 26445ecede33SGordon Ross * get a directory entry from SMB, 26455ecede33SGordon Ross * convert to a dirent, copyout. 26465ecede33SGordon Ross * We stop when there is no longer room for a 26475ecede33SGordon Ross * maximum sized dirent because we must decide 26485ecede33SGordon Ross * before we know anything about the next entry. 26495ecede33SGordon Ross */ 26505ecede33SGordon Ross while (uio->uio_resid >= dbufsiz) { 26514bff34e3Sthurlow error = smbfs_smb_findnext(ctx, limit, &scred); 26525ecede33SGordon Ross if (error != 0) 26535ecede33SGordon Ross goto out; 26544bff34e3Sthurlow np->n_dirofs++; 26555ecede33SGordon Ross 26564bff34e3Sthurlow /* Sanity check the name length. */ 26574bff34e3Sthurlow nmlen = ctx->f_nmlen; 2658613a2f6bSGordon Ross if (nmlen > SMB_MAXFNAMELEN) { 2659613a2f6bSGordon Ross nmlen = SMB_MAXFNAMELEN; 26604bff34e3Sthurlow SMBVDEBUG("Truncating name: %s\n", ctx->f_name); 26614bff34e3Sthurlow } 26624bff34e3Sthurlow if (smbfs_fastlookup) { 2663*02d09e03SGordon Ross /* See comment at smbfs_fastlookup above. */ 26645ecede33SGordon Ross if (smbfs_nget(vp, ctx->f_name, nmlen, 26655ecede33SGordon Ross &ctx->f_attr, &newvp) == 0) 26664bff34e3Sthurlow VN_RELE(newvp); 26674bff34e3Sthurlow } 26685ecede33SGordon Ross 26695ecede33SGordon Ross reclen = DIRENT64_RECLEN(nmlen); 26705ecede33SGordon Ross bzero(dp, reclen); 26715ecede33SGordon Ross dp->d_reclen = reclen; 26725ecede33SGordon Ross bcopy(ctx->f_name, dp->d_name, nmlen); 26735ecede33SGordon Ross dp->d_name[nmlen] = '\0'; 2674*02d09e03SGordon Ross dp->d_ino = ctx->f_inum; 26755ecede33SGordon Ross dp->d_off = offset + 1; /* See d_off comment above */ 26765ecede33SGordon Ross error = uiomove(dp, reclen, UIO_READ, uio); 26774bff34e3Sthurlow if (error) 26785ecede33SGordon Ross goto out; 26795ecede33SGordon Ross /* See comment re. uio_offset above. */ 26804bff34e3Sthurlow uio->uio_offset = ++offset; 26814bff34e3Sthurlow } 26825ecede33SGordon Ross 26834bff34e3Sthurlow out: 26845ecede33SGordon Ross /* 26855ecede33SGordon Ross * When we come to the end of a directory, the 26865ecede33SGordon Ross * SMB-level functions return ENOENT, but the 26875ecede33SGordon Ross * caller is not expecting an error return. 26885ecede33SGordon Ross * 26895ecede33SGordon Ross * Also note that we must delay the call to 26905ecede33SGordon Ross * smbfs_smb_findclose(np->n_dirseq, ...) 26915ecede33SGordon Ross * until smbfs_close so that all reads at the 26925ecede33SGordon Ross * end of the directory will return no data. 26935ecede33SGordon Ross */ 26945ecede33SGordon Ross if (error == ENOENT) { 26955ecede33SGordon Ross error = 0; 26965ecede33SGordon Ross if (eofp) 26975ecede33SGordon Ross *eofp = 1; 26985ecede33SGordon Ross } 26995ecede33SGordon Ross /* 27005ecede33SGordon Ross * If we encountered an error (i.e. "access denied") 27015ecede33SGordon Ross * from the FindFirst call, we will have copied out 27025ecede33SGordon Ross * the "." and ".." entries leaving offset == 2. 27035ecede33SGordon Ross * In that case, restore the original offset/resid 27045ecede33SGordon Ross * so the caller gets no data with the error. 27055ecede33SGordon Ross */ 27065ecede33SGordon Ross if (error != 0 && offset == FIRST_DIROFS) { 27075ecede33SGordon Ross uio->uio_loffset = save_offset; 27085ecede33SGordon Ross uio->uio_resid = save_resid; 27095ecede33SGordon Ross } 27105ecede33SGordon Ross SMBVDEBUG("out: offset=%d, resid=%d\n", 27115ecede33SGordon Ross (int)uio->uio_offset, (int)uio->uio_resid); 27125ecede33SGordon Ross 27134bff34e3Sthurlow kmem_free(dp, dbufsiz); 27144bff34e3Sthurlow smb_credrele(&scred); 27154bff34e3Sthurlow return (error); 27164bff34e3Sthurlow } 27174bff34e3Sthurlow 27184bff34e3Sthurlow 27194bff34e3Sthurlow /* 27204bff34e3Sthurlow * The pair of functions VOP_RWLOCK, VOP_RWUNLOCK 27214bff34e3Sthurlow * are optional functions that are called by: 27224bff34e3Sthurlow * getdents, before/after VOP_READDIR 27234bff34e3Sthurlow * pread, before/after ... VOP_READ 27244bff34e3Sthurlow * pwrite, before/after ... VOP_WRITE 27254bff34e3Sthurlow * (other places) 27264bff34e3Sthurlow * 27274bff34e3Sthurlow * Careful here: None of the above check for any 27284bff34e3Sthurlow * error returns from VOP_RWLOCK / VOP_RWUNLOCK! 27294bff34e3Sthurlow * In fact, the return value from _rwlock is NOT 27304bff34e3Sthurlow * an error code, but V_WRITELOCK_TRUE / _FALSE. 27314bff34e3Sthurlow * 27324bff34e3Sthurlow * Therefore, it's up to _this_ code to make sure 27334bff34e3Sthurlow * the lock state remains balanced, which means 27344bff34e3Sthurlow * we can't "bail out" on interrupts, etc. 27354bff34e3Sthurlow */ 27364bff34e3Sthurlow 27374bff34e3Sthurlow /* ARGSUSED2 */ 27384bff34e3Sthurlow static int 27394bff34e3Sthurlow smbfs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp) 27404bff34e3Sthurlow { 27414bff34e3Sthurlow smbnode_t *np = VTOSMB(vp); 27424bff34e3Sthurlow 27434bff34e3Sthurlow if (!write_lock) { 27444bff34e3Sthurlow (void) smbfs_rw_enter_sig(&np->r_rwlock, RW_READER, FALSE); 27454bff34e3Sthurlow return (V_WRITELOCK_FALSE); 27464bff34e3Sthurlow } 27474bff34e3Sthurlow 27484bff34e3Sthurlow 27494bff34e3Sthurlow (void) smbfs_rw_enter_sig(&np->r_rwlock, RW_WRITER, FALSE); 27504bff34e3Sthurlow return (V_WRITELOCK_TRUE); 27514bff34e3Sthurlow } 27524bff34e3Sthurlow 27534bff34e3Sthurlow /* ARGSUSED */ 27544bff34e3Sthurlow static void 27554bff34e3Sthurlow smbfs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp) 27564bff34e3Sthurlow { 27574bff34e3Sthurlow smbnode_t *np = VTOSMB(vp); 27584bff34e3Sthurlow 27594bff34e3Sthurlow smbfs_rw_exit(&np->r_rwlock); 27604bff34e3Sthurlow } 27614bff34e3Sthurlow 27624bff34e3Sthurlow 27634bff34e3Sthurlow /* ARGSUSED */ 27644bff34e3Sthurlow static int 27654bff34e3Sthurlow smbfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct) 27664bff34e3Sthurlow { 27674bff34e3Sthurlow smbmntinfo_t *smi; 27684bff34e3Sthurlow 27694bff34e3Sthurlow smi = VTOSMI(vp); 27704bff34e3Sthurlow 27714bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 27724bff34e3Sthurlow return (EPERM); 27734bff34e3Sthurlow 27744bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 27754bff34e3Sthurlow return (EIO); 27764bff34e3Sthurlow 27774bff34e3Sthurlow /* 27784bff34e3Sthurlow * Because we stuff the readdir cookie into the offset field 27794bff34e3Sthurlow * someone may attempt to do an lseek with the cookie which 27804bff34e3Sthurlow * we want to succeed. 27814bff34e3Sthurlow */ 27824bff34e3Sthurlow if (vp->v_type == VDIR) 27834bff34e3Sthurlow return (0); 27844bff34e3Sthurlow 27854bff34e3Sthurlow /* Like NFS3, just check for 63-bit overflow. */ 27864bff34e3Sthurlow if (*noffp < 0) 27874bff34e3Sthurlow return (EINVAL); 27884bff34e3Sthurlow 27894bff34e3Sthurlow return (0); 27904bff34e3Sthurlow } 27914bff34e3Sthurlow 27924bff34e3Sthurlow 27934bff34e3Sthurlow /* 27944bff34e3Sthurlow * XXX 27954bff34e3Sthurlow * This op may need to support PSARC 2007/440, nbmand changes for CIFS Service. 27964bff34e3Sthurlow */ 27974bff34e3Sthurlow static int 27984bff34e3Sthurlow smbfs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag, 27994bff34e3Sthurlow offset_t offset, struct flk_callback *flk_cbp, cred_t *cr, 28004bff34e3Sthurlow caller_context_t *ct) 28014bff34e3Sthurlow { 28024bff34e3Sthurlow if (curproc->p_zone != VTOSMI(vp)->smi_zone) 28034bff34e3Sthurlow return (EIO); 28044bff34e3Sthurlow 28054bff34e3Sthurlow if (VTOSMI(vp)->smi_flags & SMI_LLOCK) 28064bff34e3Sthurlow return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct)); 28074bff34e3Sthurlow else 28084bff34e3Sthurlow return (ENOSYS); 28094bff34e3Sthurlow } 28104bff34e3Sthurlow 28114bff34e3Sthurlow /* 28124bff34e3Sthurlow * Free storage space associated with the specified vnode. The portion 28134bff34e3Sthurlow * to be freed is specified by bfp->l_start and bfp->l_len (already 28144bff34e3Sthurlow * normalized to a "whence" of 0). 28154bff34e3Sthurlow * 28164bff34e3Sthurlow * Called by fcntl(fd, F_FREESP, lkp) for libc:ftruncate, etc. 28174bff34e3Sthurlow */ 28184bff34e3Sthurlow /* ARGSUSED */ 28194bff34e3Sthurlow static int 28204bff34e3Sthurlow smbfs_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag, 28214bff34e3Sthurlow offset_t offset, cred_t *cr, caller_context_t *ct) 28224bff34e3Sthurlow { 28234bff34e3Sthurlow int error; 28244bff34e3Sthurlow smbmntinfo_t *smi; 28254bff34e3Sthurlow 28264bff34e3Sthurlow smi = VTOSMI(vp); 28274bff34e3Sthurlow 28284bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 28294bff34e3Sthurlow return (EIO); 28304bff34e3Sthurlow 28314bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 28324bff34e3Sthurlow return (EIO); 28334bff34e3Sthurlow 283491d632c8Sgwr /* Caller (fcntl) has checked v_type */ 28354bff34e3Sthurlow ASSERT(vp->v_type == VREG); 28364bff34e3Sthurlow if (cmd != F_FREESP) 28374bff34e3Sthurlow return (EINVAL); 28384bff34e3Sthurlow 28394bff34e3Sthurlow /* 28404bff34e3Sthurlow * Like NFS3, no 32-bit offset checks here. 28414bff34e3Sthurlow * Our SMB layer takes care to return EFBIG 28424bff34e3Sthurlow * when it has to fallback to a 32-bit call. 28434bff34e3Sthurlow */ 28444bff34e3Sthurlow 28454bff34e3Sthurlow error = convoff(vp, bfp, 0, offset); 28464bff34e3Sthurlow if (!error) { 28474bff34e3Sthurlow ASSERT(bfp->l_start >= 0); 28484bff34e3Sthurlow if (bfp->l_len == 0) { 28494bff34e3Sthurlow struct vattr va; 28504bff34e3Sthurlow 28514bff34e3Sthurlow /* 28524bff34e3Sthurlow * ftruncate should not change the ctime and 28534bff34e3Sthurlow * mtime if we truncate the file to its 28544bff34e3Sthurlow * previous size. 28554bff34e3Sthurlow */ 28564bff34e3Sthurlow va.va_mask = AT_SIZE; 28574bff34e3Sthurlow error = smbfsgetattr(vp, &va, cr); 28584bff34e3Sthurlow if (error || va.va_size == bfp->l_start) 28594bff34e3Sthurlow return (error); 28604bff34e3Sthurlow va.va_mask = AT_SIZE; 28614bff34e3Sthurlow va.va_size = bfp->l_start; 28624bff34e3Sthurlow error = smbfssetattr(vp, &va, 0, cr); 28634bff34e3Sthurlow } else 28644bff34e3Sthurlow error = EINVAL; 28654bff34e3Sthurlow } 28664bff34e3Sthurlow 28674bff34e3Sthurlow return (error); 28684bff34e3Sthurlow } 28694bff34e3Sthurlow 28704bff34e3Sthurlow /* ARGSUSED */ 28714bff34e3Sthurlow static int 28724bff34e3Sthurlow smbfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr, 28734bff34e3Sthurlow caller_context_t *ct) 28744bff34e3Sthurlow { 287591d632c8Sgwr vfs_t *vfs; 28764bff34e3Sthurlow smbmntinfo_t *smi; 28774bff34e3Sthurlow struct smb_share *ssp; 28784bff34e3Sthurlow 287991d632c8Sgwr vfs = vp->v_vfsp; 288091d632c8Sgwr smi = VFTOSMI(vfs); 28814bff34e3Sthurlow 28824bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 28834bff34e3Sthurlow return (EIO); 28844bff34e3Sthurlow 28854bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 28864bff34e3Sthurlow return (EIO); 28874bff34e3Sthurlow 28884bff34e3Sthurlow switch (cmd) { 28894bff34e3Sthurlow case _PC_FILESIZEBITS: 28904bff34e3Sthurlow ssp = smi->smi_share; 28914bff34e3Sthurlow if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES) 28924bff34e3Sthurlow *valp = 64; 28934bff34e3Sthurlow else 28944bff34e3Sthurlow *valp = 32; 28954bff34e3Sthurlow break; 28964bff34e3Sthurlow 28974bff34e3Sthurlow case _PC_LINK_MAX: 28984bff34e3Sthurlow /* We only ever report one link to an object */ 28994bff34e3Sthurlow *valp = 1; 29004bff34e3Sthurlow break; 29014bff34e3Sthurlow 29027568150aSgwr case _PC_ACL_ENABLED: 29037568150aSgwr /* 2904*02d09e03SGordon Ross * Always indicate that ACLs are enabled and 2905*02d09e03SGordon Ross * that we support ACE_T format, otherwise 2906*02d09e03SGordon Ross * libsec will ask for ACLENT_T format data 2907*02d09e03SGordon Ross * which we don't support. 29087568150aSgwr */ 29097568150aSgwr *valp = _ACL_ACE_ENABLED; 29107568150aSgwr break; 29117568150aSgwr 29124bff34e3Sthurlow case _PC_SYMLINK_MAX: /* No symlinks until we do Unix extensions */ 29134bff34e3Sthurlow *valp = 0; 29144bff34e3Sthurlow break; 29154bff34e3Sthurlow 291691d632c8Sgwr case _PC_XATTR_EXISTS: 291791d632c8Sgwr if (vfs->vfs_flag & VFS_XATTR) { 291891d632c8Sgwr *valp = smbfs_xa_exists(vp, cr); 291991d632c8Sgwr break; 292091d632c8Sgwr } 292191d632c8Sgwr return (EINVAL); 292291d632c8Sgwr 29233b862e9aSRoger A. Faulkner case _PC_TIMESTAMP_RESOLUTION: 2924*02d09e03SGordon Ross /* 2925*02d09e03SGordon Ross * Windows times are tenths of microseconds 2926*02d09e03SGordon Ross * (multiples of 100 nanoseconds). 2927*02d09e03SGordon Ross */ 2928*02d09e03SGordon Ross *valp = 100L; 29293b862e9aSRoger A. Faulkner break; 29303b862e9aSRoger A. Faulkner 29314bff34e3Sthurlow default: 29324bff34e3Sthurlow return (fs_pathconf(vp, cmd, valp, cr, ct)); 29334bff34e3Sthurlow } 29344bff34e3Sthurlow return (0); 29354bff34e3Sthurlow } 29364bff34e3Sthurlow 29377568150aSgwr /* ARGSUSED */ 29387568150aSgwr static int 29397568150aSgwr smbfs_getsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr, 29407568150aSgwr caller_context_t *ct) 29417568150aSgwr { 29427568150aSgwr vfs_t *vfsp; 29437568150aSgwr smbmntinfo_t *smi; 2944*02d09e03SGordon Ross uid_t uid; 2945*02d09e03SGordon Ross gid_t gid; 2946*02d09e03SGordon Ross int error; 29477568150aSgwr uint_t mask; 29487568150aSgwr 29497568150aSgwr vfsp = vp->v_vfsp; 29507568150aSgwr smi = VFTOSMI(vfsp); 29517568150aSgwr 29527568150aSgwr if (curproc->p_zone != smi->smi_zone) 29537568150aSgwr return (EIO); 29547568150aSgwr 29557568150aSgwr if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 29567568150aSgwr return (EIO); 29577568150aSgwr 29587568150aSgwr /* 29597568150aSgwr * Our _pathconf indicates _ACL_ACE_ENABLED, 29607568150aSgwr * so we should only see VSA_ACE, etc here. 29617568150aSgwr * Note: vn_create asks for VSA_DFACLCNT, 29627568150aSgwr * and it expects ENOSYS and empty data. 29637568150aSgwr */ 29647568150aSgwr mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT | 29657568150aSgwr VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES); 29667568150aSgwr if (mask == 0) 29677568150aSgwr return (ENOSYS); 29687568150aSgwr 2969*02d09e03SGordon Ross if (smi->smi_flags & SMI_ACL) 29707568150aSgwr error = smbfs_getacl(vp, vsa, &uid, &gid, flag, cr); 2971*02d09e03SGordon Ross else 29727568150aSgwr error = ENOSYS; 29737568150aSgwr 29747568150aSgwr if (error == ENOSYS) 29757568150aSgwr error = fs_fab_acl(vp, vsa, flag, cr, ct); 29767568150aSgwr 29777568150aSgwr return (error); 29787568150aSgwr } 29797568150aSgwr 29807568150aSgwr /* ARGSUSED */ 29817568150aSgwr static int 29827568150aSgwr smbfs_setsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr, 29837568150aSgwr caller_context_t *ct) 29847568150aSgwr { 29857568150aSgwr vfs_t *vfsp; 29867568150aSgwr smbmntinfo_t *smi; 29877568150aSgwr int error; 29887568150aSgwr uint_t mask; 29897568150aSgwr 29907568150aSgwr vfsp = vp->v_vfsp; 29917568150aSgwr smi = VFTOSMI(vfsp); 29927568150aSgwr 29937568150aSgwr if (curproc->p_zone != smi->smi_zone) 29947568150aSgwr return (EIO); 29957568150aSgwr 29967568150aSgwr if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 29977568150aSgwr return (EIO); 29987568150aSgwr 29997568150aSgwr /* 30007568150aSgwr * Our _pathconf indicates _ACL_ACE_ENABLED, 30017568150aSgwr * so we should only see VSA_ACE, etc here. 30027568150aSgwr */ 30037568150aSgwr mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT); 30047568150aSgwr if (mask == 0) 30057568150aSgwr return (ENOSYS); 30067568150aSgwr 30077568150aSgwr if (vfsp->vfs_flag & VFS_RDONLY) 30087568150aSgwr return (EROFS); 30097568150aSgwr 3010*02d09e03SGordon Ross /* 3011*02d09e03SGordon Ross * Allow only the mount owner to do this. 3012*02d09e03SGordon Ross * See comments at smbfs_access_rwx. 3013*02d09e03SGordon Ross */ 3014*02d09e03SGordon Ross error = secpolicy_vnode_setdac(cr, smi->smi_uid); 3015*02d09e03SGordon Ross if (error != 0) 3016*02d09e03SGordon Ross return (error); 3017*02d09e03SGordon Ross 3018*02d09e03SGordon Ross if (smi->smi_flags & SMI_ACL) 30197568150aSgwr error = smbfs_setacl(vp, vsa, -1, -1, flag, cr); 3020*02d09e03SGordon Ross else 30217568150aSgwr error = ENOSYS; 30227568150aSgwr 30237568150aSgwr return (error); 30247568150aSgwr } 30254bff34e3Sthurlow 30264bff34e3Sthurlow 30274bff34e3Sthurlow /* 30284bff34e3Sthurlow * XXX 30294bff34e3Sthurlow * This op should eventually support PSARC 2007/268. 30304bff34e3Sthurlow */ 30314bff34e3Sthurlow static int 30324bff34e3Sthurlow smbfs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr, 30334bff34e3Sthurlow caller_context_t *ct) 30344bff34e3Sthurlow { 30354bff34e3Sthurlow if (curproc->p_zone != VTOSMI(vp)->smi_zone) 30364bff34e3Sthurlow return (EIO); 30374bff34e3Sthurlow 30384bff34e3Sthurlow if (VTOSMI(vp)->smi_flags & SMI_LLOCK) 30394bff34e3Sthurlow return (fs_shrlock(vp, cmd, shr, flag, cr, ct)); 30404bff34e3Sthurlow else 30414bff34e3Sthurlow return (ENOSYS); 30424bff34e3Sthurlow } 3043