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 /* 36134a1f4eSCasper H.S. Dik * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 374bff34e3Sthurlow */ 384bff34e3Sthurlow 394bff34e3Sthurlow #include <sys/systm.h> 404bff34e3Sthurlow #include <sys/cred.h> 414bff34e3Sthurlow #include <sys/vnode.h> 424bff34e3Sthurlow #include <sys/vfs.h> 437568150aSgwr #include <sys/filio.h> 444bff34e3Sthurlow #include <sys/uio.h> 454bff34e3Sthurlow #include <sys/dirent.h> 464bff34e3Sthurlow #include <sys/errno.h> 47613a2f6bSGordon Ross #include <sys/sunddi.h> 484bff34e3Sthurlow #include <sys/sysmacros.h> 494bff34e3Sthurlow #include <sys/kmem.h> 504bff34e3Sthurlow #include <sys/cmn_err.h> 514bff34e3Sthurlow #include <sys/vfs_opreg.h> 524bff34e3Sthurlow #include <sys/policy.h> 534bff34e3Sthurlow 544bff34e3Sthurlow #include <netsmb/smb_osdep.h> 554bff34e3Sthurlow #include <netsmb/smb.h> 564bff34e3Sthurlow #include <netsmb/smb_conn.h> 574bff34e3Sthurlow #include <netsmb/smb_subr.h> 584bff34e3Sthurlow 594bff34e3Sthurlow #include <smbfs/smbfs.h> 604bff34e3Sthurlow #include <smbfs/smbfs_node.h> 614bff34e3Sthurlow #include <smbfs/smbfs_subr.h> 624bff34e3Sthurlow 637568150aSgwr #include <sys/fs/smbfs_ioctl.h> 644bff34e3Sthurlow #include <fs/fs_subr.h> 654bff34e3Sthurlow 665ecede33SGordon Ross /* 675ecede33SGordon Ross * We assign directory offsets like the NFS client, where the 685ecede33SGordon Ross * offset increments by _one_ after each directory entry. 695ecede33SGordon Ross * Further, the entries "." and ".." are always at offsets 705ecede33SGordon Ross * zero and one (respectively) and the "real" entries from 715ecede33SGordon Ross * the server appear at offsets starting with two. This 725ecede33SGordon Ross * macro is used to initialize the n_dirofs field after 735ecede33SGordon Ross * setting n_dirseq with a _findopen call. 745ecede33SGordon Ross */ 755ecede33SGordon Ross #define FIRST_DIROFS 2 765ecede33SGordon Ross 774bff34e3Sthurlow /* 784bff34e3Sthurlow * These characters are illegal in NTFS file names. 794bff34e3Sthurlow * ref: http://support.microsoft.com/kb/147438 8091d632c8Sgwr * 8191d632c8Sgwr * Careful! The check in the XATTR case skips the 8291d632c8Sgwr * first character to allow colon in XATTR names. 834bff34e3Sthurlow */ 844bff34e3Sthurlow static const char illegal_chars[] = { 8591d632c8Sgwr ':', /* colon - keep this first! */ 864bff34e3Sthurlow '\\', /* back slash */ 874bff34e3Sthurlow '/', /* slash */ 884bff34e3Sthurlow '*', /* asterisk */ 894bff34e3Sthurlow '?', /* question mark */ 904bff34e3Sthurlow '"', /* double quote */ 914bff34e3Sthurlow '<', /* less than sign */ 924bff34e3Sthurlow '>', /* greater than sign */ 934bff34e3Sthurlow '|', /* vertical bar */ 944bff34e3Sthurlow 0 954bff34e3Sthurlow }; 964bff34e3Sthurlow 974bff34e3Sthurlow /* 984bff34e3Sthurlow * Turning this on causes nodes to be created in the cache 9902d09e03SGordon Ross * during directory listings, normally avoiding a second 10002d09e03SGordon Ross * OtW attribute fetch just after a readdir. 1014bff34e3Sthurlow */ 10202d09e03SGordon Ross int smbfs_fastlookup = 1; 1034bff34e3Sthurlow 1044bff34e3Sthurlow /* local static function defines */ 1054bff34e3Sthurlow 10602d09e03SGordon Ross static int smbfslookup_cache(vnode_t *, char *, int, vnode_t **, 10702d09e03SGordon Ross cred_t *); 1084bff34e3Sthurlow static int smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, 10902d09e03SGordon Ross int cache_ok, caller_context_t *); 1104bff34e3Sthurlow static int smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, 1114bff34e3Sthurlow cred_t *cr, caller_context_t *); 1124bff34e3Sthurlow static int smbfssetattr(vnode_t *, struct vattr *, int, cred_t *); 1134bff34e3Sthurlow static int smbfs_accessx(void *, int, cred_t *); 1144bff34e3Sthurlow static int smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp, 1154bff34e3Sthurlow caller_context_t *); 11642d15982SGordon Ross static void smbfs_rele_fid(smbnode_t *, struct smb_cred *); 11742d15982SGordon Ross 1184bff34e3Sthurlow /* 1194bff34e3Sthurlow * These are the vnode ops routines which implement the vnode interface to 1204bff34e3Sthurlow * the networked file system. These routines just take their parameters, 1214bff34e3Sthurlow * make them look networkish by putting the right info into interface structs, 1224bff34e3Sthurlow * and then calling the appropriate remote routine(s) to do the work. 1234bff34e3Sthurlow * 1244bff34e3Sthurlow * Note on directory name lookup cacheing: If we detect a stale fhandle, 1254bff34e3Sthurlow * we purge the directory cache relative to that vnode. This way, the 1264bff34e3Sthurlow * user won't get burned by the cache repeatedly. See <smbfs/smbnode.h> for 1274bff34e3Sthurlow * more details on smbnode locking. 1284bff34e3Sthurlow */ 1294bff34e3Sthurlow 1304bff34e3Sthurlow static int smbfs_open(vnode_t **, int, cred_t *, caller_context_t *); 1314bff34e3Sthurlow static int smbfs_close(vnode_t *, int, int, offset_t, cred_t *, 1324bff34e3Sthurlow caller_context_t *); 1334bff34e3Sthurlow static int smbfs_read(vnode_t *, struct uio *, int, cred_t *, 1344bff34e3Sthurlow caller_context_t *); 1354bff34e3Sthurlow static int smbfs_write(vnode_t *, struct uio *, int, cred_t *, 1364bff34e3Sthurlow caller_context_t *); 1377568150aSgwr static int smbfs_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *, 1387568150aSgwr caller_context_t *); 1394bff34e3Sthurlow static int smbfs_getattr(vnode_t *, struct vattr *, int, cred_t *, 1404bff34e3Sthurlow caller_context_t *); 1414bff34e3Sthurlow static int smbfs_setattr(vnode_t *, struct vattr *, int, cred_t *, 1424bff34e3Sthurlow caller_context_t *); 1434bff34e3Sthurlow static int smbfs_access(vnode_t *, int, int, cred_t *, caller_context_t *); 1444bff34e3Sthurlow static int smbfs_fsync(vnode_t *, int, cred_t *, caller_context_t *); 1454bff34e3Sthurlow static void smbfs_inactive(vnode_t *, cred_t *, caller_context_t *); 1464bff34e3Sthurlow static int smbfs_lookup(vnode_t *, char *, vnode_t **, struct pathname *, 1474bff34e3Sthurlow int, vnode_t *, cred_t *, caller_context_t *, 1484bff34e3Sthurlow int *, pathname_t *); 1494bff34e3Sthurlow static int smbfs_create(vnode_t *, char *, struct vattr *, enum vcexcl, 1504bff34e3Sthurlow int, vnode_t **, cred_t *, int, caller_context_t *, 1514bff34e3Sthurlow vsecattr_t *); 1524bff34e3Sthurlow static int smbfs_remove(vnode_t *, char *, cred_t *, caller_context_t *, 1534bff34e3Sthurlow int); 1544bff34e3Sthurlow static int smbfs_rename(vnode_t *, char *, vnode_t *, char *, cred_t *, 1554bff34e3Sthurlow caller_context_t *, int); 1564bff34e3Sthurlow static int smbfs_mkdir(vnode_t *, char *, struct vattr *, vnode_t **, 1574bff34e3Sthurlow cred_t *, caller_context_t *, int, vsecattr_t *); 1584bff34e3Sthurlow static int smbfs_rmdir(vnode_t *, char *, vnode_t *, cred_t *, 1594bff34e3Sthurlow caller_context_t *, int); 1604bff34e3Sthurlow static int smbfs_readdir(vnode_t *, struct uio *, cred_t *, int *, 1614bff34e3Sthurlow caller_context_t *, int); 1624bff34e3Sthurlow static int smbfs_rwlock(vnode_t *, int, caller_context_t *); 1634bff34e3Sthurlow static void smbfs_rwunlock(vnode_t *, int, caller_context_t *); 1644bff34e3Sthurlow static int smbfs_seek(vnode_t *, offset_t, offset_t *, caller_context_t *); 1654bff34e3Sthurlow static int smbfs_frlock(vnode_t *, int, struct flock64 *, int, offset_t, 1664bff34e3Sthurlow struct flk_callback *, cred_t *, caller_context_t *); 1674bff34e3Sthurlow static int smbfs_space(vnode_t *, int, struct flock64 *, int, offset_t, 1684bff34e3Sthurlow cred_t *, caller_context_t *); 1694bff34e3Sthurlow static int smbfs_pathconf(vnode_t *, int, ulong_t *, cred_t *, 1704bff34e3Sthurlow caller_context_t *); 1717568150aSgwr static int smbfs_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *, 1727568150aSgwr caller_context_t *); 1737568150aSgwr static int smbfs_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *, 1747568150aSgwr caller_context_t *); 1754bff34e3Sthurlow static int smbfs_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *, 1764bff34e3Sthurlow caller_context_t *); 1774bff34e3Sthurlow 1784bff34e3Sthurlow /* Dummy function to use until correct function is ported in */ 1794bff34e3Sthurlow int noop_vnodeop() { 1804bff34e3Sthurlow return (0); 1814bff34e3Sthurlow } 1824bff34e3Sthurlow 1834bff34e3Sthurlow struct vnodeops *smbfs_vnodeops = NULL; 1844bff34e3Sthurlow 1854bff34e3Sthurlow /* 1864bff34e3Sthurlow * Most unimplemented ops will return ENOSYS because of fs_nosys(). 1874bff34e3Sthurlow * The only ops where that won't work are ACCESS (due to open(2) 1887568150aSgwr * failures) and ... (anything else left?) 1894bff34e3Sthurlow */ 1904bff34e3Sthurlow const fs_operation_def_t smbfs_vnodeops_template[] = { 1917568150aSgwr { VOPNAME_OPEN, { .vop_open = smbfs_open } }, 1927568150aSgwr { VOPNAME_CLOSE, { .vop_close = smbfs_close } }, 1937568150aSgwr { VOPNAME_READ, { .vop_read = smbfs_read } }, 1947568150aSgwr { VOPNAME_WRITE, { .vop_write = smbfs_write } }, 1957568150aSgwr { VOPNAME_IOCTL, { .vop_ioctl = smbfs_ioctl } }, 1967568150aSgwr { VOPNAME_GETATTR, { .vop_getattr = smbfs_getattr } }, 1977568150aSgwr { VOPNAME_SETATTR, { .vop_setattr = smbfs_setattr } }, 1987568150aSgwr { VOPNAME_ACCESS, { .vop_access = smbfs_access } }, 1997568150aSgwr { VOPNAME_LOOKUP, { .vop_lookup = smbfs_lookup } }, 2007568150aSgwr { VOPNAME_CREATE, { .vop_create = smbfs_create } }, 2017568150aSgwr { VOPNAME_REMOVE, { .vop_remove = smbfs_remove } }, 2027568150aSgwr { VOPNAME_LINK, { .error = fs_nosys } }, /* smbfs_link, */ 2037568150aSgwr { VOPNAME_RENAME, { .vop_rename = smbfs_rename } }, 2047568150aSgwr { VOPNAME_MKDIR, { .vop_mkdir = smbfs_mkdir } }, 2057568150aSgwr { VOPNAME_RMDIR, { .vop_rmdir = smbfs_rmdir } }, 2067568150aSgwr { VOPNAME_READDIR, { .vop_readdir = smbfs_readdir } }, 2077568150aSgwr { VOPNAME_SYMLINK, { .error = fs_nosys } }, /* smbfs_symlink, */ 2087568150aSgwr { VOPNAME_READLINK, { .error = fs_nosys } }, /* smbfs_readlink, */ 2097568150aSgwr { VOPNAME_FSYNC, { .vop_fsync = smbfs_fsync } }, 2107568150aSgwr { VOPNAME_INACTIVE, { .vop_inactive = smbfs_inactive } }, 2117568150aSgwr { VOPNAME_FID, { .error = fs_nosys } }, /* smbfs_fid, */ 2127568150aSgwr { VOPNAME_RWLOCK, { .vop_rwlock = smbfs_rwlock } }, 2137568150aSgwr { VOPNAME_RWUNLOCK, { .vop_rwunlock = smbfs_rwunlock } }, 2147568150aSgwr { VOPNAME_SEEK, { .vop_seek = smbfs_seek } }, 2157568150aSgwr { VOPNAME_FRLOCK, { .vop_frlock = smbfs_frlock } }, 2167568150aSgwr { VOPNAME_SPACE, { .vop_space = smbfs_space } }, 2177568150aSgwr { VOPNAME_REALVP, { .error = fs_nosys } }, /* smbfs_realvp, */ 2187568150aSgwr { VOPNAME_GETPAGE, { .error = fs_nosys } }, /* smbfs_getpage, */ 2197568150aSgwr { VOPNAME_PUTPAGE, { .error = fs_nosys } }, /* smbfs_putpage, */ 2207568150aSgwr { VOPNAME_MAP, { .error = fs_nosys } }, /* smbfs_map, */ 2217568150aSgwr { VOPNAME_ADDMAP, { .error = fs_nosys } }, /* smbfs_addmap, */ 2227568150aSgwr { VOPNAME_DELMAP, { .error = fs_nosys } }, /* smbfs_delmap, */ 2237568150aSgwr { VOPNAME_DUMP, { .error = fs_nosys } }, /* smbfs_dump, */ 2247568150aSgwr { VOPNAME_PATHCONF, { .vop_pathconf = smbfs_pathconf } }, 2257568150aSgwr { VOPNAME_PAGEIO, { .error = fs_nosys } }, /* smbfs_pageio, */ 2267568150aSgwr { VOPNAME_SETSECATTR, { .vop_setsecattr = smbfs_setsecattr } }, 2277568150aSgwr { VOPNAME_GETSECATTR, { .vop_getsecattr = smbfs_getsecattr } }, 2287568150aSgwr { VOPNAME_SHRLOCK, { .vop_shrlock = smbfs_shrlock } }, 2294bff34e3Sthurlow { NULL, NULL } 2304bff34e3Sthurlow }; 2314bff34e3Sthurlow 2324bff34e3Sthurlow /* 2334bff34e3Sthurlow * XXX 2344bff34e3Sthurlow * When new and relevant functionality is enabled, we should be 2354bff34e3Sthurlow * calling vfs_set_feature() to inform callers that pieces of 2369660e5cbSJanice Chang * functionality are available, per PSARC 2007/227. 2374bff34e3Sthurlow */ 2384bff34e3Sthurlow /* ARGSUSED */ 2394bff34e3Sthurlow static int 2404bff34e3Sthurlow smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct) 2414bff34e3Sthurlow { 2424bff34e3Sthurlow smbnode_t *np; 2434bff34e3Sthurlow vnode_t *vp; 24402d09e03SGordon Ross smbfattr_t fa; 2454bff34e3Sthurlow u_int32_t rights, rightsrcvd; 2464bff34e3Sthurlow u_int16_t fid, oldfid; 247613a2f6bSGordon Ross int oldgenid; 2484bff34e3Sthurlow struct smb_cred scred; 2494bff34e3Sthurlow smbmntinfo_t *smi; 250613a2f6bSGordon Ross smb_share_t *ssp; 2514bff34e3Sthurlow cred_t *oldcr; 2524bff34e3Sthurlow int tmperror; 2534bff34e3Sthurlow int error = 0; 2544bff34e3Sthurlow 2554bff34e3Sthurlow vp = *vpp; 2564bff34e3Sthurlow np = VTOSMB(vp); 2574bff34e3Sthurlow smi = VTOSMI(vp); 258613a2f6bSGordon Ross ssp = smi->smi_share; 2594bff34e3Sthurlow 260*a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 2614bff34e3Sthurlow return (EIO); 2624bff34e3Sthurlow 2634bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 2644bff34e3Sthurlow return (EIO); 2654bff34e3Sthurlow 2664bff34e3Sthurlow if (vp->v_type != VREG && vp->v_type != VDIR) { /* XXX VLNK? */ 2674bff34e3Sthurlow SMBVDEBUG("open eacces vtype=%d\n", vp->v_type); 2684bff34e3Sthurlow return (EACCES); 2694bff34e3Sthurlow } 2704bff34e3Sthurlow 2714bff34e3Sthurlow /* 2724bff34e3Sthurlow * Get exclusive access to n_fid and related stuff. 2734bff34e3Sthurlow * No returns after this until out. 2744bff34e3Sthurlow */ 2754bff34e3Sthurlow if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp))) 2764bff34e3Sthurlow return (EINTR); 277613a2f6bSGordon Ross smb_credinit(&scred, cr); 2784bff34e3Sthurlow 27991d632c8Sgwr /* 28091d632c8Sgwr * Keep track of the vnode type at first open. 28191d632c8Sgwr * It may change later, and we need close to do 28291d632c8Sgwr * cleanup for the type we opened. Also deny 28391d632c8Sgwr * open of new types until old type is closed. 28491d632c8Sgwr * XXX: Per-open instance nodes whould help. 28591d632c8Sgwr */ 28691d632c8Sgwr if (np->n_ovtype == VNON) { 28791d632c8Sgwr ASSERT(np->n_dirrefs == 0); 28891d632c8Sgwr ASSERT(np->n_fidrefs == 0); 28991d632c8Sgwr } else if (np->n_ovtype != vp->v_type) { 29091d632c8Sgwr SMBVDEBUG("open n_ovtype=%d v_type=%d\n", 29191d632c8Sgwr np->n_ovtype, vp->v_type); 29291d632c8Sgwr error = EACCES; 29391d632c8Sgwr goto out; 29491d632c8Sgwr } 29591d632c8Sgwr 2964bff34e3Sthurlow /* 2975ecede33SGordon Ross * Directory open. See smbfs_readvdir() 2984bff34e3Sthurlow */ 2994bff34e3Sthurlow if (vp->v_type == VDIR) { 3005ecede33SGordon Ross if (np->n_dirseq == NULL) { 3015ecede33SGordon Ross /* first open */ 3025ecede33SGordon Ross error = smbfs_smb_findopen(np, "*", 1, 3035ecede33SGordon Ross SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, 3045ecede33SGordon Ross &scred, &np->n_dirseq); 3055ecede33SGordon Ross if (error != 0) 3065ecede33SGordon Ross goto out; 3075ecede33SGordon Ross } 3085ecede33SGordon Ross np->n_dirofs = FIRST_DIROFS; 3094bff34e3Sthurlow np->n_dirrefs++; 3104bff34e3Sthurlow goto have_fid; 3114bff34e3Sthurlow } 3124bff34e3Sthurlow 3134bff34e3Sthurlow /* 3144bff34e3Sthurlow * If caller specified O_TRUNC/FTRUNC, then be sure to set 3154bff34e3Sthurlow * FWRITE (to drive successful setattr(size=0) after open) 3164bff34e3Sthurlow */ 3174bff34e3Sthurlow if (flag & FTRUNC) 3184bff34e3Sthurlow flag |= FWRITE; 3194bff34e3Sthurlow 3204bff34e3Sthurlow /* 321613a2f6bSGordon Ross * If we already have it open, and the FID is still valid, 322613a2f6bSGordon Ross * check whether the rights are sufficient for FID reuse. 3234bff34e3Sthurlow */ 324613a2f6bSGordon Ross if (np->n_fidrefs > 0 && 325613a2f6bSGordon Ross np->n_vcgenid == ssp->ss_vcgenid) { 3264bff34e3Sthurlow int upgrade = 0; 3274bff34e3Sthurlow 3284bff34e3Sthurlow if ((flag & FWRITE) && 32902d09e03SGordon Ross !(np->n_rights & SA_RIGHT_FILE_WRITE_DATA)) 3304bff34e3Sthurlow upgrade = 1; 3314bff34e3Sthurlow if ((flag & FREAD) && 33202d09e03SGordon Ross !(np->n_rights & SA_RIGHT_FILE_READ_DATA)) 3334bff34e3Sthurlow upgrade = 1; 3344bff34e3Sthurlow if (!upgrade) { 3354bff34e3Sthurlow /* 3364bff34e3Sthurlow * the existing open is good enough 3374bff34e3Sthurlow */ 3384bff34e3Sthurlow np->n_fidrefs++; 3394bff34e3Sthurlow goto have_fid; 3404bff34e3Sthurlow } 3414bff34e3Sthurlow } 3424bff34e3Sthurlow rights = np->n_fidrefs ? np->n_rights : 0; 3434bff34e3Sthurlow 3444bff34e3Sthurlow /* 3454bff34e3Sthurlow * we always ask for READ_CONTROL so we can always get the 34691d632c8Sgwr * owner/group IDs to satisfy a stat. Ditto attributes. 3474bff34e3Sthurlow */ 34891d632c8Sgwr rights |= (STD_RIGHT_READ_CONTROL_ACCESS | 34991d632c8Sgwr SA_RIGHT_FILE_READ_ATTRIBUTES); 3504bff34e3Sthurlow if ((flag & FREAD)) 3514bff34e3Sthurlow rights |= SA_RIGHT_FILE_READ_DATA; 3524bff34e3Sthurlow if ((flag & FWRITE)) 35302d09e03SGordon Ross rights |= SA_RIGHT_FILE_WRITE_DATA | 35402d09e03SGordon Ross SA_RIGHT_FILE_APPEND_DATA | 35502d09e03SGordon Ross SA_RIGHT_FILE_WRITE_ATTRIBUTES; 35602d09e03SGordon Ross 35702d09e03SGordon Ross bzero(&fa, sizeof (fa)); 35802d09e03SGordon Ross error = smbfs_smb_open(np, 35902d09e03SGordon Ross NULL, 0, 0, /* name nmlen xattr */ 36002d09e03SGordon Ross rights, &scred, 36102d09e03SGordon Ross &fid, &rightsrcvd, &fa); 3624bff34e3Sthurlow if (error) 3634bff34e3Sthurlow goto out; 36402d09e03SGordon Ross smbfs_attrcache_fa(vp, &fa); 3654bff34e3Sthurlow 3664bff34e3Sthurlow /* 3674bff34e3Sthurlow * We have a new FID and access rights. 3684bff34e3Sthurlow */ 3694bff34e3Sthurlow oldfid = np->n_fid; 370613a2f6bSGordon Ross oldgenid = np->n_vcgenid; 3714bff34e3Sthurlow np->n_fid = fid; 372613a2f6bSGordon Ross np->n_vcgenid = ssp->ss_vcgenid; 3734bff34e3Sthurlow np->n_rights = rightsrcvd; 3744bff34e3Sthurlow np->n_fidrefs++; 375613a2f6bSGordon Ross if (np->n_fidrefs > 1 && 376613a2f6bSGordon Ross oldgenid == ssp->ss_vcgenid) { 3774bff34e3Sthurlow /* 3784bff34e3Sthurlow * We already had it open (presumably because 3794bff34e3Sthurlow * it was open with insufficient rights.) 3804bff34e3Sthurlow * Close old wire-open. 3814bff34e3Sthurlow */ 382613a2f6bSGordon Ross tmperror = smbfs_smb_close(ssp, 38302d09e03SGordon Ross oldfid, NULL, &scred); 3844bff34e3Sthurlow if (tmperror) 3854bff34e3Sthurlow SMBVDEBUG("error %d closing %s\n", 3864bff34e3Sthurlow tmperror, np->n_rpath); 3874bff34e3Sthurlow } 3884bff34e3Sthurlow 3894bff34e3Sthurlow /* 3904bff34e3Sthurlow * This thread did the open. 3914bff34e3Sthurlow * Save our credentials too. 3924bff34e3Sthurlow */ 3934bff34e3Sthurlow mutex_enter(&np->r_statelock); 3944bff34e3Sthurlow oldcr = np->r_cred; 3954bff34e3Sthurlow np->r_cred = cr; 3964bff34e3Sthurlow crhold(cr); 3974bff34e3Sthurlow if (oldcr) 3984bff34e3Sthurlow crfree(oldcr); 3994bff34e3Sthurlow mutex_exit(&np->r_statelock); 4004bff34e3Sthurlow 4014bff34e3Sthurlow have_fid: 40291d632c8Sgwr /* 40391d632c8Sgwr * Keep track of the vnode type at first open. 40491d632c8Sgwr * (see comments above) 40591d632c8Sgwr */ 40691d632c8Sgwr if (np->n_ovtype == VNON) 40791d632c8Sgwr np->n_ovtype = vp->v_type; 4084bff34e3Sthurlow 4094bff34e3Sthurlow out: 4104bff34e3Sthurlow smb_credrele(&scred); 4114bff34e3Sthurlow smbfs_rw_exit(&np->r_lkserlock); 4124bff34e3Sthurlow return (error); 4134bff34e3Sthurlow } 4144bff34e3Sthurlow 4154bff34e3Sthurlow /*ARGSUSED*/ 4164bff34e3Sthurlow static int 4174bff34e3Sthurlow smbfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr, 4184bff34e3Sthurlow caller_context_t *ct) 4194bff34e3Sthurlow { 4204bff34e3Sthurlow smbnode_t *np; 421613a2f6bSGordon Ross smbmntinfo_t *smi; 4224bff34e3Sthurlow struct smb_cred scred; 4234bff34e3Sthurlow 4244bff34e3Sthurlow np = VTOSMB(vp); 425613a2f6bSGordon Ross smi = VTOSMI(vp); 4264bff34e3Sthurlow 4274bff34e3Sthurlow /* 4284bff34e3Sthurlow * Don't "bail out" for VFS_UNMOUNTED here, 4294bff34e3Sthurlow * as we want to do cleanup, etc. 4304bff34e3Sthurlow */ 4314bff34e3Sthurlow 4324bff34e3Sthurlow /* 4334bff34e3Sthurlow * zone_enter(2) prevents processes from changing zones with SMBFS files 4344bff34e3Sthurlow * open; if we happen to get here from the wrong zone we can't do 4354bff34e3Sthurlow * anything over the wire. 4364bff34e3Sthurlow */ 437*a19609f8Sjv if (smi->smi_zone_ref.zref_zone != curproc->p_zone) { 4384bff34e3Sthurlow /* 4394bff34e3Sthurlow * We could attempt to clean up locks, except we're sure 4404bff34e3Sthurlow * that the current process didn't acquire any locks on 4414bff34e3Sthurlow * the file: any attempt to lock a file belong to another zone 4424bff34e3Sthurlow * will fail, and one can't lock an SMBFS file and then change 4434bff34e3Sthurlow * zones, as that fails too. 4444bff34e3Sthurlow * 4454bff34e3Sthurlow * Returning an error here is the sane thing to do. A 4464bff34e3Sthurlow * subsequent call to VN_RELE() which translates to a 4474bff34e3Sthurlow * smbfs_inactive() will clean up state: if the zone of the 4484bff34e3Sthurlow * vnode's origin is still alive and kicking, an async worker 4494bff34e3Sthurlow * thread will handle the request (from the correct zone), and 4504bff34e3Sthurlow * everything (minus the final smbfs_getattr_otw() call) should 4514bff34e3Sthurlow * be OK. If the zone is going away smbfs_async_inactive() will 4524bff34e3Sthurlow * throw away cached pages inline. 4534bff34e3Sthurlow */ 4544bff34e3Sthurlow return (EIO); 4554bff34e3Sthurlow } 4564bff34e3Sthurlow 4574bff34e3Sthurlow /* 4584bff34e3Sthurlow * If we are using local locking for this filesystem, then 4594bff34e3Sthurlow * release all of the SYSV style record locks. Otherwise, 4604bff34e3Sthurlow * we are doing network locking and we need to release all 4614bff34e3Sthurlow * of the network locks. All of the locks held by this 4624bff34e3Sthurlow * process on this file are released no matter what the 4634bff34e3Sthurlow * incoming reference count is. 4644bff34e3Sthurlow */ 46542d15982SGordon Ross if (smi->smi_flags & SMI_LLOCK) { 466613a2f6bSGordon Ross pid_t pid = ddi_get_pid(); 467613a2f6bSGordon Ross cleanlocks(vp, pid, 0); 468613a2f6bSGordon Ross cleanshares(vp, pid); 4694bff34e3Sthurlow } 4704bff34e3Sthurlow 4714bff34e3Sthurlow /* 47202d09e03SGordon Ross * This (passed in) count is the ref. count from the 47302d09e03SGordon Ross * user's file_t before the closef call (fio.c). 47402d09e03SGordon Ross * We only care when the reference goes away. 4754bff34e3Sthurlow */ 47602d09e03SGordon Ross if (count > 1) 47702d09e03SGordon Ross return (0); 4784bff34e3Sthurlow 4794bff34e3Sthurlow /* 48042d15982SGordon Ross * Decrement the reference count for the FID 48142d15982SGordon Ross * and possibly do the OtW close. 48242d15982SGordon Ross * 4834bff34e3Sthurlow * Exclusive lock for modifying n_fid stuff. 4844bff34e3Sthurlow * Don't want this one ever interruptible. 4854bff34e3Sthurlow */ 4864bff34e3Sthurlow (void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0); 487613a2f6bSGordon Ross smb_credinit(&scred, cr); 4884bff34e3Sthurlow 48942d15982SGordon Ross smbfs_rele_fid(np, &scred); 49042d15982SGordon Ross 49142d15982SGordon Ross smb_credrele(&scred); 49242d15982SGordon Ross smbfs_rw_exit(&np->r_lkserlock); 49342d15982SGordon Ross 49442d15982SGordon Ross return (0); 49542d15982SGordon Ross } 49642d15982SGordon Ross 49742d15982SGordon Ross /* 49842d15982SGordon Ross * Helper for smbfs_close. Decrement the reference count 49942d15982SGordon Ross * for an SMB-level file or directory ID, and when the last 50042d15982SGordon Ross * reference for the fid goes away, do the OtW close. 50142d15982SGordon Ross * Also called in smbfs_inactive (defensive cleanup). 50242d15982SGordon Ross */ 50342d15982SGordon Ross static void 50442d15982SGordon Ross smbfs_rele_fid(smbnode_t *np, struct smb_cred *scred) 50542d15982SGordon Ross { 50642d15982SGordon Ross smb_share_t *ssp; 50742d15982SGordon Ross cred_t *oldcr; 50842d15982SGordon Ross struct smbfs_fctx *fctx; 50942d15982SGordon Ross int error; 51042d15982SGordon Ross uint16_t ofid; 51142d15982SGordon Ross 51242d15982SGordon Ross ssp = np->n_mount->smi_share; 5134bff34e3Sthurlow error = 0; 51491d632c8Sgwr 51542d15982SGordon Ross /* Make sure we serialize for n_dirseq use. */ 51642d15982SGordon Ross ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_WRITER)); 51742d15982SGordon Ross 51891d632c8Sgwr /* 51991d632c8Sgwr * Note that vp->v_type may change if a remote node 52091d632c8Sgwr * is deleted and recreated as a different type, and 52191d632c8Sgwr * our getattr may change v_type accordingly. 52291d632c8Sgwr * Now use n_ovtype to keep track of the v_type 52391d632c8Sgwr * we had during open (see comments above). 52491d632c8Sgwr */ 52542d15982SGordon Ross switch (np->n_ovtype) { 52642d15982SGordon Ross case VDIR: 5274bff34e3Sthurlow ASSERT(np->n_dirrefs > 0); 5284bff34e3Sthurlow if (--np->n_dirrefs) 52942d15982SGordon Ross return; 5304bff34e3Sthurlow if ((fctx = np->n_dirseq) != NULL) { 5314bff34e3Sthurlow np->n_dirseq = NULL; 5325ecede33SGordon Ross np->n_dirofs = 0; 53342d15982SGordon Ross error = smbfs_smb_findclose(fctx, scred); 5344bff34e3Sthurlow } 53542d15982SGordon Ross break; 53642d15982SGordon Ross 53742d15982SGordon Ross case VREG: 5384bff34e3Sthurlow ASSERT(np->n_fidrefs > 0); 5394bff34e3Sthurlow if (--np->n_fidrefs) 54042d15982SGordon Ross return; 5414bff34e3Sthurlow if ((ofid = np->n_fid) != SMB_FID_UNUSED) { 5424bff34e3Sthurlow np->n_fid = SMB_FID_UNUSED; 543613a2f6bSGordon Ross /* After reconnect, n_fid is invalid */ 544613a2f6bSGordon Ross if (np->n_vcgenid == ssp->ss_vcgenid) { 545613a2f6bSGordon Ross error = smbfs_smb_close( 54642d15982SGordon Ross ssp, ofid, NULL, scred); 547613a2f6bSGordon Ross } 5484bff34e3Sthurlow } 54942d15982SGordon Ross break; 55042d15982SGordon Ross 55142d15982SGordon Ross default: 55242d15982SGordon Ross SMBVDEBUG("bad n_ovtype %d\n", np->n_ovtype); 55342d15982SGordon Ross break; 5544bff34e3Sthurlow } 5554bff34e3Sthurlow if (error) { 55602d09e03SGordon Ross SMBVDEBUG("error %d closing %s\n", 5574bff34e3Sthurlow error, np->n_rpath); 5584bff34e3Sthurlow } 5594bff34e3Sthurlow 56091d632c8Sgwr /* Allow next open to use any v_type. */ 56191d632c8Sgwr np->n_ovtype = VNON; 56291d632c8Sgwr 56302d09e03SGordon Ross /* 56402d09e03SGordon Ross * Other "last close" stuff. 56502d09e03SGordon Ross */ 56602d09e03SGordon Ross mutex_enter(&np->r_statelock); 5674bff34e3Sthurlow if (np->n_flag & NATTRCHANGED) 56802d09e03SGordon Ross smbfs_attrcache_rm_locked(np); 56902d09e03SGordon Ross oldcr = np->r_cred; 57002d09e03SGordon Ross np->r_cred = NULL; 57102d09e03SGordon Ross mutex_exit(&np->r_statelock); 57202d09e03SGordon Ross if (oldcr != NULL) 57302d09e03SGordon Ross crfree(oldcr); 5744bff34e3Sthurlow } 5754bff34e3Sthurlow 5764bff34e3Sthurlow /* ARGSUSED */ 5774bff34e3Sthurlow static int 5784bff34e3Sthurlow smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr, 5794bff34e3Sthurlow caller_context_t *ct) 5804bff34e3Sthurlow { 5819c9af259SGordon Ross struct smb_cred scred; 5829c9af259SGordon Ross struct vattr va; 583613a2f6bSGordon Ross smbnode_t *np; 584613a2f6bSGordon Ross smbmntinfo_t *smi; 585613a2f6bSGordon Ross smb_share_t *ssp; 5869c9af259SGordon Ross offset_t endoff; 5879c9af259SGordon Ross ssize_t past_eof; 5889c9af259SGordon Ross int error; 5894bff34e3Sthurlow 5904bff34e3Sthurlow np = VTOSMB(vp); 5914bff34e3Sthurlow smi = VTOSMI(vp); 592613a2f6bSGordon Ross ssp = smi->smi_share; 5934bff34e3Sthurlow 594*a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 5954bff34e3Sthurlow return (EIO); 5964bff34e3Sthurlow 5974bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 5984bff34e3Sthurlow return (EIO); 5994bff34e3Sthurlow 6004bff34e3Sthurlow ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER)); 6014bff34e3Sthurlow 6024bff34e3Sthurlow if (vp->v_type != VREG) 6034bff34e3Sthurlow return (EISDIR); 6044bff34e3Sthurlow 6054bff34e3Sthurlow if (uiop->uio_resid == 0) 6064bff34e3Sthurlow return (0); 6074bff34e3Sthurlow 6084bff34e3Sthurlow /* 6094bff34e3Sthurlow * Like NFS3, just check for 63-bit overflow. 6104bff34e3Sthurlow * Our SMB layer takes care to return EFBIG 6114bff34e3Sthurlow * when it has to fallback to a 32-bit call. 6124bff34e3Sthurlow */ 613613a2f6bSGordon Ross endoff = uiop->uio_loffset + uiop->uio_resid; 614613a2f6bSGordon Ross if (uiop->uio_loffset < 0 || endoff < 0) 6154bff34e3Sthurlow return (EINVAL); 6164bff34e3Sthurlow 6174bff34e3Sthurlow /* get vnode attributes from server */ 6184bff34e3Sthurlow va.va_mask = AT_SIZE | AT_MTIME; 6194bff34e3Sthurlow if (error = smbfsgetattr(vp, &va, cr)) 6209c9af259SGordon Ross return (error); 6214bff34e3Sthurlow 6229c9af259SGordon Ross /* Update mtime with mtime from server here? */ 6239c9af259SGordon Ross 6249c9af259SGordon Ross /* if offset is beyond EOF, read nothing */ 6259c9af259SGordon Ross if (uiop->uio_loffset >= va.va_size) 6269c9af259SGordon Ross return (0); 6274bff34e3Sthurlow 6284bff34e3Sthurlow /* 6299c9af259SGordon Ross * Limit the read to the remaining file size. 6309c9af259SGordon Ross * Do this by temporarily reducing uio_resid 6319c9af259SGordon Ross * by the amount the lies beyoned the EOF. 6324bff34e3Sthurlow */ 6339c9af259SGordon Ross if (endoff > va.va_size) { 6349c9af259SGordon Ross past_eof = (ssize_t)(endoff - va.va_size); 6359c9af259SGordon Ross uiop->uio_resid -= past_eof; 6369c9af259SGordon Ross } else 6379c9af259SGordon Ross past_eof = 0; 6389c9af259SGordon Ross 6399c9af259SGordon Ross /* Shared lock for n_fid use in smb_rwuio */ 6409c9af259SGordon Ross if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) 6419c9af259SGordon Ross return (EINTR); 642613a2f6bSGordon Ross smb_credinit(&scred, cr); 6434bff34e3Sthurlow 644613a2f6bSGordon Ross /* After reconnect, n_fid is invalid */ 645613a2f6bSGordon Ross if (np->n_vcgenid != ssp->ss_vcgenid) 646613a2f6bSGordon Ross error = ESTALE; 647613a2f6bSGordon Ross else 648613a2f6bSGordon Ross error = smb_rwuio(ssp, np->n_fid, UIO_READ, 649613a2f6bSGordon Ross uiop, &scred, smb_timo_read); 6509c9af259SGordon Ross 6519c9af259SGordon Ross smb_credrele(&scred); 6524bff34e3Sthurlow smbfs_rw_exit(&np->r_lkserlock); 6534bff34e3Sthurlow 6549c9af259SGordon Ross /* undo adjustment of resid */ 6559c9af259SGordon Ross uiop->uio_resid += past_eof; 6569c9af259SGordon Ross 6579c9af259SGordon Ross return (error); 6584bff34e3Sthurlow } 6594bff34e3Sthurlow 6604bff34e3Sthurlow 6614bff34e3Sthurlow /* ARGSUSED */ 6624bff34e3Sthurlow static int 6634bff34e3Sthurlow smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr, 6644bff34e3Sthurlow caller_context_t *ct) 6654bff34e3Sthurlow { 6669c9af259SGordon Ross struct smb_cred scred; 6679c9af259SGordon Ross struct vattr va; 668613a2f6bSGordon Ross smbnode_t *np; 669613a2f6bSGordon Ross smbmntinfo_t *smi; 670613a2f6bSGordon Ross smb_share_t *ssp; 6719c9af259SGordon Ross offset_t endoff, limit; 6729c9af259SGordon Ross ssize_t past_limit; 6739c9af259SGordon Ross int error, timo; 6744bff34e3Sthurlow 6754bff34e3Sthurlow np = VTOSMB(vp); 6764bff34e3Sthurlow smi = VTOSMI(vp); 677613a2f6bSGordon Ross ssp = smi->smi_share; 6784bff34e3Sthurlow 679*a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 6804bff34e3Sthurlow return (EIO); 6814bff34e3Sthurlow 6824bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 6834bff34e3Sthurlow return (EIO); 6844bff34e3Sthurlow 6854bff34e3Sthurlow ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_WRITER)); 6864bff34e3Sthurlow 6874bff34e3Sthurlow if (vp->v_type != VREG) 6884bff34e3Sthurlow return (EISDIR); 6894bff34e3Sthurlow 6904bff34e3Sthurlow if (uiop->uio_resid == 0) 6914bff34e3Sthurlow return (0); 6924bff34e3Sthurlow 6939c9af259SGordon Ross /* 6949c9af259SGordon Ross * Handle ioflag bits: (FAPPEND|FSYNC|FDSYNC) 6959c9af259SGordon Ross */ 6969c9af259SGordon Ross if (ioflag & (FAPPEND | FSYNC)) { 6979c9af259SGordon Ross if (np->n_flag & NMODIFIED) { 69802d09e03SGordon Ross smbfs_attrcache_remove(np); 6999c9af259SGordon Ross /* XXX: smbfs_vinvalbuf? */ 7009c9af259SGordon Ross } 7019c9af259SGordon Ross } 7029c9af259SGordon Ross if (ioflag & FAPPEND) { 7039c9af259SGordon Ross /* 7049c9af259SGordon Ross * File size can be changed by another client 7059c9af259SGordon Ross */ 7069c9af259SGordon Ross va.va_mask = AT_SIZE; 7079c9af259SGordon Ross if (error = smbfsgetattr(vp, &va, cr)) 7089c9af259SGordon Ross return (error); 7099c9af259SGordon Ross uiop->uio_loffset = va.va_size; 7109c9af259SGordon Ross } 7114bff34e3Sthurlow 7129c9af259SGordon Ross /* 7139c9af259SGordon Ross * Like NFS3, just check for 63-bit overflow. 7149c9af259SGordon Ross */ 7159c9af259SGordon Ross endoff = uiop->uio_loffset + uiop->uio_resid; 7169c9af259SGordon Ross if (uiop->uio_loffset < 0 || endoff < 0) 7179c9af259SGordon Ross return (EINVAL); 7184bff34e3Sthurlow 7194bff34e3Sthurlow /* 7209c9af259SGordon Ross * Check to make sure that the process will not exceed 7219c9af259SGordon Ross * its limit on file size. It is okay to write up to 7229c9af259SGordon Ross * the limit, but not beyond. Thus, the write which 7239c9af259SGordon Ross * reaches the limit will be short and the next write 7249c9af259SGordon Ross * will return an error. 7259c9af259SGordon Ross * 7269c9af259SGordon Ross * So if we're starting at or beyond the limit, EFBIG. 7279c9af259SGordon Ross * Otherwise, temporarily reduce resid to the amount 7289c9af259SGordon Ross * the falls after the limit. 7294bff34e3Sthurlow */ 7309c9af259SGordon Ross limit = uiop->uio_llimit; 7319c9af259SGordon Ross if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T) 7329c9af259SGordon Ross limit = MAXOFFSET_T; 7339c9af259SGordon Ross if (uiop->uio_loffset >= limit) 7349c9af259SGordon Ross return (EFBIG); 7359c9af259SGordon Ross if (endoff > limit) { 7369c9af259SGordon Ross past_limit = (ssize_t)(endoff - limit); 7379c9af259SGordon Ross uiop->uio_resid -= past_limit; 7389c9af259SGordon Ross } else 7399c9af259SGordon Ross past_limit = 0; 7409c9af259SGordon Ross 7419c9af259SGordon Ross /* Timeout: longer for append. */ 7429c9af259SGordon Ross timo = smb_timo_write; 74302d09e03SGordon Ross if (endoff > np->r_size) 7449c9af259SGordon Ross timo = smb_timo_append; 7459c9af259SGordon Ross 7469c9af259SGordon Ross /* Shared lock for n_fid use in smb_rwuio */ 7479c9af259SGordon Ross if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) 7489c9af259SGordon Ross return (EINTR); 749613a2f6bSGordon Ross smb_credinit(&scred, cr); 7504bff34e3Sthurlow 751613a2f6bSGordon Ross /* After reconnect, n_fid is invalid */ 752613a2f6bSGordon Ross if (np->n_vcgenid != ssp->ss_vcgenid) 753613a2f6bSGordon Ross error = ESTALE; 754613a2f6bSGordon Ross else 755613a2f6bSGordon Ross error = smb_rwuio(ssp, np->n_fid, UIO_WRITE, 756613a2f6bSGordon Ross uiop, &scred, timo); 7579c9af259SGordon Ross 7589c9af259SGordon Ross if (error == 0) { 7599c9af259SGordon Ross mutex_enter(&np->r_statelock); 7609c9af259SGordon Ross np->n_flag |= (NFLUSHWIRE | NATTRCHANGED); 76102d09e03SGordon Ross if (uiop->uio_loffset > (offset_t)np->r_size) 76202d09e03SGordon Ross np->r_size = (len_t)uiop->uio_loffset; 7639c9af259SGordon Ross mutex_exit(&np->r_statelock); 7649c9af259SGordon Ross if (ioflag & (FSYNC|FDSYNC)) { 7659c9af259SGordon Ross /* Don't error the I/O if this fails. */ 7669c9af259SGordon Ross (void) smbfs_smb_flush(np, &scred); 7679c9af259SGordon Ross } 7689c9af259SGordon Ross } 7699c9af259SGordon Ross 7709c9af259SGordon Ross smb_credrele(&scred); 7714bff34e3Sthurlow smbfs_rw_exit(&np->r_lkserlock); 7724bff34e3Sthurlow 7739c9af259SGordon Ross /* undo adjustment of resid */ 7749c9af259SGordon Ross uiop->uio_resid += past_limit; 7759c9af259SGordon Ross 7769c9af259SGordon Ross return (error); 7774bff34e3Sthurlow } 7784bff34e3Sthurlow 7794bff34e3Sthurlow 7807568150aSgwr /* ARGSUSED */ 7817568150aSgwr static int 7827568150aSgwr smbfs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, 7837568150aSgwr cred_t *cr, int *rvalp, caller_context_t *ct) 7847568150aSgwr { 7857568150aSgwr int error; 7867568150aSgwr smbmntinfo_t *smi; 7877568150aSgwr 7887568150aSgwr smi = VTOSMI(vp); 7897568150aSgwr 790*a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 7917568150aSgwr return (EIO); 7927568150aSgwr 7937568150aSgwr if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 7947568150aSgwr return (EIO); 7957568150aSgwr 7967568150aSgwr switch (cmd) { 7977568150aSgwr /* First three from ZFS. XXX - need these? */ 7987568150aSgwr 7997568150aSgwr case _FIOFFS: 8007568150aSgwr error = smbfs_fsync(vp, 0, cr, ct); 8017568150aSgwr break; 8027568150aSgwr 8037568150aSgwr /* 8047568150aSgwr * The following two ioctls are used by bfu. 8057568150aSgwr * Silently ignore to avoid bfu errors. 8067568150aSgwr */ 8077568150aSgwr case _FIOGDIO: 8087568150aSgwr case _FIOSDIO: 8097568150aSgwr error = 0; 8107568150aSgwr break; 8117568150aSgwr 8127568150aSgwr #ifdef NOT_YET /* XXX - from the NFS code. */ 8137568150aSgwr case _FIODIRECTIO: 8147568150aSgwr error = smbfs_directio(vp, (int)arg, cr); 8157568150aSgwr #endif 8167568150aSgwr 8177568150aSgwr /* 8187568150aSgwr * Allow get/set with "raw" security descriptor (SD) data. 8197568150aSgwr * Useful for testing, diagnosing idmap problems, etc. 8207568150aSgwr */ 8217568150aSgwr case SMBFSIO_GETSD: 822bd7c6f51SGordon Ross error = smbfs_acl_iocget(vp, arg, flag, cr); 8237568150aSgwr break; 8247568150aSgwr 8257568150aSgwr case SMBFSIO_SETSD: 826bd7c6f51SGordon Ross error = smbfs_acl_iocset(vp, arg, flag, cr); 8277568150aSgwr break; 8287568150aSgwr 8297568150aSgwr default: 8307568150aSgwr error = ENOTTY; 8317568150aSgwr break; 8327568150aSgwr } 8337568150aSgwr 8347568150aSgwr return (error); 8357568150aSgwr } 8367568150aSgwr 8377568150aSgwr 8384bff34e3Sthurlow /* 8394bff34e3Sthurlow * Return either cached or remote attributes. If get remote attr 8404bff34e3Sthurlow * use them to check and invalidate caches, then cache the new attributes. 8414bff34e3Sthurlow * 8424bff34e3Sthurlow * XXX 8434bff34e3Sthurlow * This op should eventually support PSARC 2007/315, Extensible Attribute 8444bff34e3Sthurlow * Interfaces, for richer metadata. 8454bff34e3Sthurlow */ 8464bff34e3Sthurlow /* ARGSUSED */ 8474bff34e3Sthurlow static int 8484bff34e3Sthurlow smbfs_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr, 8494bff34e3Sthurlow caller_context_t *ct) 8504bff34e3Sthurlow { 8514bff34e3Sthurlow smbnode_t *np; 8524bff34e3Sthurlow smbmntinfo_t *smi; 8534bff34e3Sthurlow 8544bff34e3Sthurlow smi = VTOSMI(vp); 8554bff34e3Sthurlow 856*a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 8574bff34e3Sthurlow return (EIO); 8584bff34e3Sthurlow 8594bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 8604bff34e3Sthurlow return (EIO); 8614bff34e3Sthurlow 8624bff34e3Sthurlow /* 8634bff34e3Sthurlow * If it has been specified that the return value will 8644bff34e3Sthurlow * just be used as a hint, and we are only being asked 8654bff34e3Sthurlow * for size, fsid or rdevid, then return the client's 8664bff34e3Sthurlow * notion of these values without checking to make sure 8674bff34e3Sthurlow * that the attribute cache is up to date. 8684bff34e3Sthurlow * The whole point is to avoid an over the wire GETATTR 8694bff34e3Sthurlow * call. 8704bff34e3Sthurlow */ 8714bff34e3Sthurlow np = VTOSMB(vp); 8724bff34e3Sthurlow if (flags & ATTR_HINT) { 8734bff34e3Sthurlow if (vap->va_mask == 8744bff34e3Sthurlow (vap->va_mask & (AT_SIZE | AT_FSID | AT_RDEV))) { 8754bff34e3Sthurlow mutex_enter(&np->r_statelock); 8764bff34e3Sthurlow if (vap->va_mask | AT_SIZE) 8774bff34e3Sthurlow vap->va_size = np->r_size; 8784bff34e3Sthurlow if (vap->va_mask | AT_FSID) 87902d09e03SGordon Ross vap->va_fsid = vp->v_vfsp->vfs_dev; 8804bff34e3Sthurlow if (vap->va_mask | AT_RDEV) 88102d09e03SGordon Ross vap->va_rdev = vp->v_rdev; 8824bff34e3Sthurlow mutex_exit(&np->r_statelock); 8834bff34e3Sthurlow return (0); 8844bff34e3Sthurlow } 8854bff34e3Sthurlow } 8864bff34e3Sthurlow 8874bff34e3Sthurlow return (smbfsgetattr(vp, vap, cr)); 8884bff34e3Sthurlow } 8894bff34e3Sthurlow 89002d09e03SGordon Ross /* smbfsgetattr() in smbfs_client.c */ 8914bff34e3Sthurlow 8924bff34e3Sthurlow /* 8934bff34e3Sthurlow * XXX 8944bff34e3Sthurlow * This op should eventually support PSARC 2007/315, Extensible Attribute 8954bff34e3Sthurlow * Interfaces, for richer metadata. 8964bff34e3Sthurlow */ 8974bff34e3Sthurlow /*ARGSUSED4*/ 8984bff34e3Sthurlow static int 8994bff34e3Sthurlow smbfs_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr, 9004bff34e3Sthurlow caller_context_t *ct) 9014bff34e3Sthurlow { 90202d09e03SGordon Ross vfs_t *vfsp; 90302d09e03SGordon Ross smbmntinfo_t *smi; 9044bff34e3Sthurlow int error; 9054bff34e3Sthurlow uint_t mask; 9064bff34e3Sthurlow struct vattr oldva; 9074bff34e3Sthurlow 90802d09e03SGordon Ross vfsp = vp->v_vfsp; 90902d09e03SGordon Ross smi = VFTOSMI(vfsp); 9104bff34e3Sthurlow 911*a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 9124bff34e3Sthurlow return (EIO); 9134bff34e3Sthurlow 91402d09e03SGordon Ross if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 9154bff34e3Sthurlow return (EIO); 9164bff34e3Sthurlow 9174bff34e3Sthurlow mask = vap->va_mask; 9184bff34e3Sthurlow if (mask & AT_NOSET) 9194bff34e3Sthurlow return (EINVAL); 9204bff34e3Sthurlow 92102d09e03SGordon Ross if (vfsp->vfs_flag & VFS_RDONLY) 92202d09e03SGordon Ross return (EROFS); 92302d09e03SGordon Ross 924bd7c6f51SGordon Ross /* 925bd7c6f51SGordon Ross * This is a _local_ access check so that only the owner of 926bd7c6f51SGordon Ross * this mount can set attributes. With ACLs enabled, the 927bd7c6f51SGordon Ross * file owner can be different from the mount owner, and we 928bd7c6f51SGordon Ross * need to check the _mount_ owner here. See _access_rwx 929bd7c6f51SGordon Ross */ 93002d09e03SGordon Ross bzero(&oldva, sizeof (oldva)); 931bd7c6f51SGordon Ross oldva.va_mask = AT_TYPE | AT_MODE; 9324bff34e3Sthurlow error = smbfsgetattr(vp, &oldva, cr); 9334bff34e3Sthurlow if (error) 9344bff34e3Sthurlow return (error); 935bd7c6f51SGordon Ross oldva.va_mask |= AT_UID | AT_GID; 936bd7c6f51SGordon Ross oldva.va_uid = smi->smi_uid; 937bd7c6f51SGordon Ross oldva.va_gid = smi->smi_gid; 9384bff34e3Sthurlow 9394bff34e3Sthurlow error = secpolicy_vnode_setattr(cr, vp, vap, &oldva, flags, 9404bff34e3Sthurlow smbfs_accessx, vp); 9414bff34e3Sthurlow if (error) 9424bff34e3Sthurlow return (error); 9434bff34e3Sthurlow 944bd7c6f51SGordon Ross if (mask & (AT_UID | AT_GID)) { 945bd7c6f51SGordon Ross if (smi->smi_flags & SMI_ACL) 946bd7c6f51SGordon Ross error = smbfs_acl_setids(vp, vap, cr); 947bd7c6f51SGordon Ross else 948bd7c6f51SGordon Ross error = ENOSYS; 949bd7c6f51SGordon Ross if (error != 0) { 950bd7c6f51SGordon Ross SMBVDEBUG("error %d seting UID/GID on %s", 951bd7c6f51SGordon Ross error, VTOSMB(vp)->n_rpath); 952bd7c6f51SGordon Ross /* 953bd7c6f51SGordon Ross * It might be more correct to return the 954bd7c6f51SGordon Ross * error here, but that causes complaints 955bd7c6f51SGordon Ross * when root extracts a cpio archive, etc. 956bd7c6f51SGordon Ross * So ignore this error, and go ahead with 957bd7c6f51SGordon Ross * the rest of the setattr work. 958bd7c6f51SGordon Ross */ 959bd7c6f51SGordon Ross } 960bd7c6f51SGordon Ross } 961bd7c6f51SGordon Ross 9624bff34e3Sthurlow return (smbfssetattr(vp, vap, flags, cr)); 9634bff34e3Sthurlow } 9644bff34e3Sthurlow 9654bff34e3Sthurlow /* 9664bff34e3Sthurlow * Mostly from Darwin smbfs_setattr() 9674bff34e3Sthurlow * but then modified a lot. 9684bff34e3Sthurlow */ 9694bff34e3Sthurlow /* ARGSUSED */ 9704bff34e3Sthurlow static int 9714bff34e3Sthurlow smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr) 9724bff34e3Sthurlow { 9734bff34e3Sthurlow int error = 0; 9744bff34e3Sthurlow smbnode_t *np = VTOSMB(vp); 9754bff34e3Sthurlow uint_t mask = vap->va_mask; 9764bff34e3Sthurlow struct timespec *mtime, *atime; 9774bff34e3Sthurlow struct smb_cred scred; 9784bff34e3Sthurlow int cerror, modified = 0; 9794bff34e3Sthurlow unsigned short fid; 9804bff34e3Sthurlow int have_fid = 0; 9814bff34e3Sthurlow uint32_t rights = 0; 9824bff34e3Sthurlow 983*a19609f8Sjv ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone_ref.zref_zone); 9844bff34e3Sthurlow 98591d632c8Sgwr /* 98691d632c8Sgwr * There are no settable attributes on the XATTR dir, 98791d632c8Sgwr * so just silently ignore these. On XATTR files, 98891d632c8Sgwr * you can set the size but nothing else. 98991d632c8Sgwr */ 99091d632c8Sgwr if (vp->v_flag & V_XATTRDIR) 99191d632c8Sgwr return (0); 99291d632c8Sgwr if (np->n_flag & N_XATTR) { 99391d632c8Sgwr if (mask & AT_TIMES) 99491d632c8Sgwr SMBVDEBUG("ignore set time on xattr\n"); 99591d632c8Sgwr mask &= AT_SIZE; 99691d632c8Sgwr } 99791d632c8Sgwr 9984bff34e3Sthurlow /* 9994bff34e3Sthurlow * If our caller is trying to set multiple attributes, they 10004bff34e3Sthurlow * can make no assumption about what order they are done in. 10014bff34e3Sthurlow * Here we try to do them in order of decreasing likelihood 10024bff34e3Sthurlow * of failure, just to minimize the chance we'll wind up 10034bff34e3Sthurlow * with a partially complete request. 10044bff34e3Sthurlow */ 10054bff34e3Sthurlow 10064bff34e3Sthurlow /* Shared lock for (possible) n_fid use. */ 10074bff34e3Sthurlow if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) 10084bff34e3Sthurlow return (EINTR); 1009613a2f6bSGordon Ross smb_credinit(&scred, cr); 10104bff34e3Sthurlow 10114bff34e3Sthurlow /* 10124bff34e3Sthurlow * Will we need an open handle for this setattr? 10134bff34e3Sthurlow * If so, what rights will we need? 10144bff34e3Sthurlow */ 10154bff34e3Sthurlow if (mask & (AT_ATIME | AT_MTIME)) { 10164bff34e3Sthurlow rights |= 101702d09e03SGordon Ross SA_RIGHT_FILE_WRITE_ATTRIBUTES; 10184bff34e3Sthurlow } 10194bff34e3Sthurlow if (mask & AT_SIZE) { 10204bff34e3Sthurlow rights |= 10214bff34e3Sthurlow SA_RIGHT_FILE_WRITE_DATA | 10224bff34e3Sthurlow SA_RIGHT_FILE_APPEND_DATA; 102302d09e03SGordon Ross } 102402d09e03SGordon Ross 102502d09e03SGordon Ross /* 102602d09e03SGordon Ross * Only SIZE really requires a handle, but it's 102702d09e03SGordon Ross * simpler and more reliable to set via a handle. 102802d09e03SGordon Ross * Some servers like NT4 won't set times by path. 102902d09e03SGordon Ross * Also, we're usually setting everything anyway. 103002d09e03SGordon Ross */ 103102d09e03SGordon Ross if (mask & (AT_SIZE | AT_ATIME | AT_MTIME)) { 10324bff34e3Sthurlow error = smbfs_smb_tmpopen(np, rights, &scred, &fid); 10334bff34e3Sthurlow if (error) { 10344bff34e3Sthurlow SMBVDEBUG("error %d opening %s\n", 10354bff34e3Sthurlow error, np->n_rpath); 10364bff34e3Sthurlow goto out; 10374bff34e3Sthurlow } 10384bff34e3Sthurlow have_fid = 1; 10394bff34e3Sthurlow } 10404bff34e3Sthurlow 10414bff34e3Sthurlow /* 10424bff34e3Sthurlow * If the server supports the UNIX extensions, right here is where 10434bff34e3Sthurlow * we'd support changes to uid, gid, mode, and possibly va_flags. 10444bff34e3Sthurlow * For now we claim to have made any such changes. 10454bff34e3Sthurlow */ 10464bff34e3Sthurlow 10474bff34e3Sthurlow if (mask & AT_SIZE) { 10484bff34e3Sthurlow /* 10494bff34e3Sthurlow * If the new file size is less than what the client sees as 10504bff34e3Sthurlow * the file size, then just change the size and invalidate 10514bff34e3Sthurlow * the pages. 10524bff34e3Sthurlow * I am commenting this code at present because the function 10534bff34e3Sthurlow * smbfs_putapage() is not yet implemented. 10544bff34e3Sthurlow */ 10554bff34e3Sthurlow 10564bff34e3Sthurlow /* 10574bff34e3Sthurlow * Set the file size to vap->va_size. 10584bff34e3Sthurlow */ 10594bff34e3Sthurlow ASSERT(have_fid); 10604bff34e3Sthurlow error = smbfs_smb_setfsize(np, fid, vap->va_size, &scred); 10614bff34e3Sthurlow if (error) { 10624bff34e3Sthurlow SMBVDEBUG("setsize error %d file %s\n", 10634bff34e3Sthurlow error, np->n_rpath); 10644bff34e3Sthurlow } else { 10654bff34e3Sthurlow /* 10664bff34e3Sthurlow * Darwin had code here to zero-extend. 10674bff34e3Sthurlow * Tests indicate the server will zero-fill, 10684bff34e3Sthurlow * so looks like we don't need to do this. 10694bff34e3Sthurlow * Good thing, as this could take forever. 1070613a2f6bSGordon Ross * 1071613a2f6bSGordon Ross * XXX: Reportedly, writing one byte of zero 1072613a2f6bSGordon Ross * at the end offset avoids problems here. 10734bff34e3Sthurlow */ 10744bff34e3Sthurlow mutex_enter(&np->r_statelock); 10754bff34e3Sthurlow np->r_size = vap->va_size; 10764bff34e3Sthurlow mutex_exit(&np->r_statelock); 10774bff34e3Sthurlow modified = 1; 10784bff34e3Sthurlow } 10794bff34e3Sthurlow } 10804bff34e3Sthurlow 10814bff34e3Sthurlow /* 10824bff34e3Sthurlow * XXX: When Solaris has create_time, set that too. 10834bff34e3Sthurlow * Note: create_time is different from ctime. 10844bff34e3Sthurlow */ 10854bff34e3Sthurlow mtime = ((mask & AT_MTIME) ? &vap->va_mtime : 0); 10864bff34e3Sthurlow atime = ((mask & AT_ATIME) ? &vap->va_atime : 0); 10874bff34e3Sthurlow 10884bff34e3Sthurlow if (mtime || atime) { 10894bff34e3Sthurlow /* 109002d09e03SGordon Ross * Always use the handle-based set attr call now. 109102d09e03SGordon Ross * Not trying to set DOS attributes here so pass zero. 10924bff34e3Sthurlow */ 109302d09e03SGordon Ross ASSERT(have_fid); 109402d09e03SGordon Ross error = smbfs_smb_setfattr(np, fid, 109502d09e03SGordon Ross 0, mtime, atime, &scred); 10964bff34e3Sthurlow if (error) { 10974bff34e3Sthurlow SMBVDEBUG("set times error %d file %s\n", 10984bff34e3Sthurlow error, np->n_rpath); 10994bff34e3Sthurlow } else { 11004bff34e3Sthurlow modified = 1; 11014bff34e3Sthurlow } 11024bff34e3Sthurlow } 11034bff34e3Sthurlow 11044bff34e3Sthurlow out: 11054bff34e3Sthurlow if (modified) { 11064bff34e3Sthurlow /* 110702d09e03SGordon Ross * Invalidate attribute cache in case the server 110802d09e03SGordon Ross * doesn't set exactly the attributes we asked. 11094bff34e3Sthurlow */ 111002d09e03SGordon Ross smbfs_attrcache_remove(np); 11114bff34e3Sthurlow } 11124bff34e3Sthurlow 11134bff34e3Sthurlow if (have_fid) { 11144bff34e3Sthurlow cerror = smbfs_smb_tmpclose(np, fid, &scred); 11154bff34e3Sthurlow if (cerror) 111602d09e03SGordon Ross SMBVDEBUG("error %d closing %s\n", 11174bff34e3Sthurlow cerror, np->n_rpath); 11184bff34e3Sthurlow } 11194bff34e3Sthurlow 11204bff34e3Sthurlow smb_credrele(&scred); 11214bff34e3Sthurlow smbfs_rw_exit(&np->r_lkserlock); 11224bff34e3Sthurlow 11234bff34e3Sthurlow return (error); 11244bff34e3Sthurlow } 11254bff34e3Sthurlow 11264bff34e3Sthurlow /* 11274bff34e3Sthurlow * smbfs_access_rwx() 11284bff34e3Sthurlow * Common function for smbfs_access, etc. 11294bff34e3Sthurlow * 11304bff34e3Sthurlow * The security model implemented by the FS is unusual 1131bd7c6f51SGordon Ross * due to the current "single user mounts" restriction: 11324bff34e3Sthurlow * All access under a given mount point uses the CIFS 11334bff34e3Sthurlow * credentials established by the owner of the mount. 11344bff34e3Sthurlow * 11354bff34e3Sthurlow * Most access checking is handled by the CIFS server, 11364bff34e3Sthurlow * but we need sufficient Unix access checks here to 11374bff34e3Sthurlow * prevent other local Unix users from having access 11384bff34e3Sthurlow * to objects under this mount that the uid/gid/mode 11394bff34e3Sthurlow * settings in the mount would not allow. 11404bff34e3Sthurlow * 11414bff34e3Sthurlow * With this model, there is a case where we need the 11424bff34e3Sthurlow * ability to do an access check before we have the 11434bff34e3Sthurlow * vnode for an object. This function takes advantage 11444bff34e3Sthurlow * of the fact that the uid/gid/mode is per mount, and 11454bff34e3Sthurlow * avoids the need for a vnode. 11464bff34e3Sthurlow * 11474bff34e3Sthurlow * We still (sort of) need a vnode when we call 11484bff34e3Sthurlow * secpolicy_vnode_access, but that only uses 11494bff34e3Sthurlow * the vtype field, so we can use a pair of fake 11504bff34e3Sthurlow * vnodes that have only v_type filled in. 11514bff34e3Sthurlow * 11524bff34e3Sthurlow * XXX: Later, add a new secpolicy_vtype_access() 11534bff34e3Sthurlow * that takes the vtype instead of a vnode, and 11544bff34e3Sthurlow * get rid of the tmpl_vxxx fake vnodes below. 11554bff34e3Sthurlow */ 11564bff34e3Sthurlow static int 11574bff34e3Sthurlow smbfs_access_rwx(vfs_t *vfsp, int vtype, int mode, cred_t *cr) 11584bff34e3Sthurlow { 11594bff34e3Sthurlow /* See the secpolicy call below. */ 11604bff34e3Sthurlow static const vnode_t tmpl_vdir = { .v_type = VDIR }; 11614bff34e3Sthurlow static const vnode_t tmpl_vreg = { .v_type = VREG }; 11624bff34e3Sthurlow vattr_t va; 11634bff34e3Sthurlow vnode_t *tvp; 11644bff34e3Sthurlow struct smbmntinfo *smi = VFTOSMI(vfsp); 11654bff34e3Sthurlow int shift = 0; 11664bff34e3Sthurlow 11674bff34e3Sthurlow /* 11684bff34e3Sthurlow * Build our (fabricated) vnode attributes. 11694bff34e3Sthurlow * XXX: Could make these templates in the 11704bff34e3Sthurlow * per-mount struct and use them here. 11714bff34e3Sthurlow */ 11724bff34e3Sthurlow bzero(&va, sizeof (va)); 11734bff34e3Sthurlow va.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID; 11744bff34e3Sthurlow va.va_type = vtype; 11754bff34e3Sthurlow va.va_mode = (vtype == VDIR) ? 117602d09e03SGordon Ross smi->smi_dmode : smi->smi_fmode; 117702d09e03SGordon Ross va.va_uid = smi->smi_uid; 117802d09e03SGordon Ross va.va_gid = smi->smi_gid; 11794bff34e3Sthurlow 11804bff34e3Sthurlow /* 11814bff34e3Sthurlow * Disallow write attempts on read-only file systems, 11824bff34e3Sthurlow * unless the file is a device or fifo node. Note: 11834bff34e3Sthurlow * Inline vn_is_readonly and IS_DEVVP here because 11844bff34e3Sthurlow * we may not have a vnode ptr. Original expr. was: 11854bff34e3Sthurlow * (mode & VWRITE) && vn_is_readonly(vp) && !IS_DEVVP(vp)) 11864bff34e3Sthurlow */ 11874bff34e3Sthurlow if ((mode & VWRITE) && 11884bff34e3Sthurlow (vfsp->vfs_flag & VFS_RDONLY) && 11894bff34e3Sthurlow !(vtype == VCHR || vtype == VBLK || vtype == VFIFO)) 11904bff34e3Sthurlow return (EROFS); 11914bff34e3Sthurlow 11924bff34e3Sthurlow /* 11934bff34e3Sthurlow * Disallow attempts to access mandatory lock files. 11944bff34e3Sthurlow * Similarly, expand MANDLOCK here. 11954bff34e3Sthurlow * XXX: not sure we need this. 11964bff34e3Sthurlow */ 11974bff34e3Sthurlow if ((mode & (VWRITE | VREAD | VEXEC)) && 11984bff34e3Sthurlow va.va_type == VREG && MANDMODE(va.va_mode)) 11994bff34e3Sthurlow return (EACCES); 12004bff34e3Sthurlow 12014bff34e3Sthurlow /* 12024bff34e3Sthurlow * Access check is based on only 12034bff34e3Sthurlow * one of owner, group, public. 12044bff34e3Sthurlow * If not owner, then check group. 12054bff34e3Sthurlow * If not a member of the group, 12064bff34e3Sthurlow * then check public access. 12074bff34e3Sthurlow */ 12084bff34e3Sthurlow if (crgetuid(cr) != va.va_uid) { 12094bff34e3Sthurlow shift += 3; 12104bff34e3Sthurlow if (!groupmember(va.va_gid, cr)) 12114bff34e3Sthurlow shift += 3; 12124bff34e3Sthurlow } 12134bff34e3Sthurlow 12144bff34e3Sthurlow /* 12154bff34e3Sthurlow * We need a vnode for secpolicy_vnode_access, 12164bff34e3Sthurlow * but the only thing it looks at is v_type, 12174bff34e3Sthurlow * so pass one of the templates above. 12184bff34e3Sthurlow */ 12194bff34e3Sthurlow tvp = (va.va_type == VDIR) ? 12204bff34e3Sthurlow (vnode_t *)&tmpl_vdir : 12214bff34e3Sthurlow (vnode_t *)&tmpl_vreg; 1222134a1f4eSCasper H.S. Dik 1223134a1f4eSCasper H.S. Dik return (secpolicy_vnode_access2(cr, tvp, va.va_uid, 1224134a1f4eSCasper H.S. Dik va.va_mode << shift, mode)); 12254bff34e3Sthurlow } 12264bff34e3Sthurlow 12274bff34e3Sthurlow /* 12284bff34e3Sthurlow * See smbfs_setattr 12294bff34e3Sthurlow */ 12304bff34e3Sthurlow static int 12314bff34e3Sthurlow smbfs_accessx(void *arg, int mode, cred_t *cr) 12324bff34e3Sthurlow { 12334bff34e3Sthurlow vnode_t *vp = arg; 12344bff34e3Sthurlow /* 12354bff34e3Sthurlow * Note: The caller has checked the current zone, 12364bff34e3Sthurlow * the SMI_DEAD and VFS_UNMOUNTED flags, etc. 12374bff34e3Sthurlow */ 12384bff34e3Sthurlow return (smbfs_access_rwx(vp->v_vfsp, vp->v_type, mode, cr)); 12394bff34e3Sthurlow } 12404bff34e3Sthurlow 12414bff34e3Sthurlow /* 12424bff34e3Sthurlow * XXX 12434bff34e3Sthurlow * This op should support PSARC 2007/403, Modified Access Checks for CIFS 12444bff34e3Sthurlow */ 12454bff34e3Sthurlow /* ARGSUSED */ 12464bff34e3Sthurlow static int 12474bff34e3Sthurlow smbfs_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct) 12484bff34e3Sthurlow { 12494bff34e3Sthurlow vfs_t *vfsp; 12504bff34e3Sthurlow smbmntinfo_t *smi; 12514bff34e3Sthurlow 12524bff34e3Sthurlow vfsp = vp->v_vfsp; 12534bff34e3Sthurlow smi = VFTOSMI(vfsp); 12544bff34e3Sthurlow 1255*a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 12564bff34e3Sthurlow return (EIO); 12574bff34e3Sthurlow 12584bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 12594bff34e3Sthurlow return (EIO); 12604bff34e3Sthurlow 12614bff34e3Sthurlow return (smbfs_access_rwx(vfsp, vp->v_type, mode, cr)); 12624bff34e3Sthurlow } 12634bff34e3Sthurlow 12644bff34e3Sthurlow 12654bff34e3Sthurlow /* 12664bff34e3Sthurlow * Flush local dirty pages to stable storage on the server. 12674bff34e3Sthurlow * 12684bff34e3Sthurlow * If FNODSYNC is specified, then there is nothing to do because 12694bff34e3Sthurlow * metadata changes are not cached on the client before being 12704bff34e3Sthurlow * sent to the server. 12714bff34e3Sthurlow */ 12724bff34e3Sthurlow /* ARGSUSED */ 12734bff34e3Sthurlow static int 12744bff34e3Sthurlow smbfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct) 12754bff34e3Sthurlow { 12764bff34e3Sthurlow int error = 0; 12774bff34e3Sthurlow smbmntinfo_t *smi; 12782f5e3e91SGordon Ross smbnode_t *np; 12792f5e3e91SGordon Ross struct smb_cred scred; 12804bff34e3Sthurlow 12812f5e3e91SGordon Ross np = VTOSMB(vp); 12824bff34e3Sthurlow smi = VTOSMI(vp); 12834bff34e3Sthurlow 1284*a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 12854bff34e3Sthurlow return (EIO); 12864bff34e3Sthurlow 12874bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 12884bff34e3Sthurlow return (EIO); 12894bff34e3Sthurlow 12904bff34e3Sthurlow if ((syncflag & FNODSYNC) || IS_SWAPVP(vp)) 12914bff34e3Sthurlow return (0); 12924bff34e3Sthurlow 12932f5e3e91SGordon Ross if ((syncflag & (FSYNC|FDSYNC)) == 0) 12942f5e3e91SGordon Ross return (0); 12952f5e3e91SGordon Ross 12962f5e3e91SGordon Ross /* Shared lock for n_fid use in _flush */ 12972f5e3e91SGordon Ross if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) 12982f5e3e91SGordon Ross return (EINTR); 1299613a2f6bSGordon Ross smb_credinit(&scred, cr); 13002f5e3e91SGordon Ross 13012f5e3e91SGordon Ross error = smbfs_smb_flush(np, &scred); 13022f5e3e91SGordon Ross 13032f5e3e91SGordon Ross smb_credrele(&scred); 13042f5e3e91SGordon Ross smbfs_rw_exit(&np->r_lkserlock); 13052f5e3e91SGordon Ross 13064bff34e3Sthurlow return (error); 13074bff34e3Sthurlow } 13084bff34e3Sthurlow 13094bff34e3Sthurlow /* 13104bff34e3Sthurlow * Last reference to vnode went away. 13114bff34e3Sthurlow */ 13124bff34e3Sthurlow /* ARGSUSED */ 13134bff34e3Sthurlow static void 13144bff34e3Sthurlow smbfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct) 13154bff34e3Sthurlow { 13164bff34e3Sthurlow smbnode_t *np; 131742d15982SGordon Ross struct smb_cred scred; 13184bff34e3Sthurlow 13194bff34e3Sthurlow /* 13204bff34e3Sthurlow * Don't "bail out" for VFS_UNMOUNTED here, 13214bff34e3Sthurlow * as we want to do cleanup, etc. 13224bff34e3Sthurlow * See also pcfs_inactive 13234bff34e3Sthurlow */ 13244bff34e3Sthurlow 13254bff34e3Sthurlow np = VTOSMB(vp); 13264bff34e3Sthurlow 13274bff34e3Sthurlow /* 13284bff34e3Sthurlow * If this is coming from the wrong zone, we let someone in the right 13294bff34e3Sthurlow * zone take care of it asynchronously. We can get here due to 13304bff34e3Sthurlow * VN_RELE() being called from pageout() or fsflush(). This call may 13314bff34e3Sthurlow * potentially turn into an expensive no-op if, for instance, v_count 13324bff34e3Sthurlow * gets incremented in the meantime, but it's still correct. 13334bff34e3Sthurlow */ 13344bff34e3Sthurlow 13354bff34e3Sthurlow /* 133642d15982SGordon Ross * Defend against the possibility that higher-level callers 133742d15982SGordon Ross * might not correctly balance open and close calls. If we 133842d15982SGordon Ross * get here with open references remaining, it means there 133942d15982SGordon Ross * was a missing VOP_CLOSE somewhere. If that happens, do 134042d15982SGordon Ross * the close here so we don't "leak" FIDs on the server. 13414bff34e3Sthurlow * 134242d15982SGordon Ross * Exclusive lock for modifying n_fid stuff. 134342d15982SGordon Ross * Don't want this one ever interruptible. 13444bff34e3Sthurlow */ 134542d15982SGordon Ross (void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0); 134642d15982SGordon Ross smb_credinit(&scred, cr); 134742d15982SGordon Ross 134842d15982SGordon Ross switch (np->n_ovtype) { 134942d15982SGordon Ross case VNON: 135042d15982SGordon Ross /* not open (OK) */ 135142d15982SGordon Ross break; 135242d15982SGordon Ross 135342d15982SGordon Ross case VDIR: 135442d15982SGordon Ross if (np->n_dirrefs == 0) 135542d15982SGordon Ross break; 135642d15982SGordon Ross SMBVDEBUG("open dir: refs %d path %s\n", 135742d15982SGordon Ross np->n_dirrefs, np->n_rpath); 135842d15982SGordon Ross /* Force last close. */ 135942d15982SGordon Ross np->n_dirrefs = 1; 136042d15982SGordon Ross smbfs_rele_fid(np, &scred); 136142d15982SGordon Ross break; 136242d15982SGordon Ross 136342d15982SGordon Ross case VREG: 136442d15982SGordon Ross if (np->n_fidrefs == 0) 136542d15982SGordon Ross break; 136642d15982SGordon Ross SMBVDEBUG("open file: refs %d id 0x%x path %s\n", 13674bff34e3Sthurlow np->n_fidrefs, np->n_fid, np->n_rpath); 136842d15982SGordon Ross /* Force last close. */ 136942d15982SGordon Ross np->n_fidrefs = 1; 137042d15982SGordon Ross smbfs_rele_fid(np, &scred); 137142d15982SGordon Ross break; 137242d15982SGordon Ross 137342d15982SGordon Ross default: 137442d15982SGordon Ross SMBVDEBUG("bad n_ovtype %d\n", np->n_ovtype); 137542d15982SGordon Ross np->n_ovtype = VNON; 137642d15982SGordon Ross break; 13774bff34e3Sthurlow } 137842d15982SGordon Ross 137942d15982SGordon Ross smb_credrele(&scred); 138042d15982SGordon Ross smbfs_rw_exit(&np->r_lkserlock); 13814bff34e3Sthurlow 138202d09e03SGordon Ross smbfs_addfree(np); 13834bff34e3Sthurlow } 13844bff34e3Sthurlow 13854bff34e3Sthurlow /* 13864bff34e3Sthurlow * Remote file system operations having to do with directory manipulation. 13874bff34e3Sthurlow */ 13884bff34e3Sthurlow /* ARGSUSED */ 13894bff34e3Sthurlow static int 13904bff34e3Sthurlow smbfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp, 13914bff34e3Sthurlow int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct, 13924bff34e3Sthurlow int *direntflags, pathname_t *realpnp) 13934bff34e3Sthurlow { 139491d632c8Sgwr vfs_t *vfs; 13954bff34e3Sthurlow smbmntinfo_t *smi; 139691d632c8Sgwr smbnode_t *dnp; 139791d632c8Sgwr int error; 13984bff34e3Sthurlow 139991d632c8Sgwr vfs = dvp->v_vfsp; 140091d632c8Sgwr smi = VFTOSMI(vfs); 14014bff34e3Sthurlow 1402*a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 14034bff34e3Sthurlow return (EPERM); 14044bff34e3Sthurlow 140591d632c8Sgwr if (smi->smi_flags & SMI_DEAD || vfs->vfs_flag & VFS_UNMOUNTED) 14064bff34e3Sthurlow return (EIO); 14074bff34e3Sthurlow 14084bff34e3Sthurlow dnp = VTOSMB(dvp); 140991d632c8Sgwr 141091d632c8Sgwr /* 141191d632c8Sgwr * Are we looking up extended attributes? If so, "dvp" is 141291d632c8Sgwr * the file or directory for which we want attributes, and 141391d632c8Sgwr * we need a lookup of the (faked up) attribute directory 141491d632c8Sgwr * before we lookup the rest of the path. 141591d632c8Sgwr */ 141691d632c8Sgwr if (flags & LOOKUP_XATTR) { 141791d632c8Sgwr /* 141891d632c8Sgwr * Require the xattr mount option. 141991d632c8Sgwr */ 142091d632c8Sgwr if ((vfs->vfs_flag & VFS_XATTR) == 0) 142191d632c8Sgwr return (EINVAL); 142291d632c8Sgwr 142391d632c8Sgwr error = smbfs_get_xattrdir(dvp, vpp, cr, flags); 142491d632c8Sgwr return (error); 142591d632c8Sgwr } 142691d632c8Sgwr 142702d09e03SGordon Ross if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_READER, SMBINTR(dvp))) 142802d09e03SGordon Ross return (EINTR); 14294bff34e3Sthurlow 14304bff34e3Sthurlow error = smbfslookup(dvp, nm, vpp, cr, 1, ct); 14314bff34e3Sthurlow 14324bff34e3Sthurlow smbfs_rw_exit(&dnp->r_rwlock); 14334bff34e3Sthurlow 14344bff34e3Sthurlow return (error); 14354bff34e3Sthurlow } 14364bff34e3Sthurlow 14374bff34e3Sthurlow /* ARGSUSED */ 14384bff34e3Sthurlow static int 143902d09e03SGordon Ross smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, 144002d09e03SGordon Ross int cache_ok, caller_context_t *ct) 14414bff34e3Sthurlow { 14424bff34e3Sthurlow int error; 14434bff34e3Sthurlow int supplen; /* supported length */ 14444bff34e3Sthurlow vnode_t *vp; 144502d09e03SGordon Ross smbnode_t *np; 14464bff34e3Sthurlow smbnode_t *dnp; 14474bff34e3Sthurlow smbmntinfo_t *smi; 14484bff34e3Sthurlow /* struct smb_vc *vcp; */ 144991d632c8Sgwr const char *ill; 14504bff34e3Sthurlow const char *name = (const char *)nm; 14514bff34e3Sthurlow int nmlen = strlen(nm); 14524bff34e3Sthurlow int rplen; 14534bff34e3Sthurlow struct smb_cred scred; 14544bff34e3Sthurlow struct smbfattr fa; 14554bff34e3Sthurlow 14564bff34e3Sthurlow smi = VTOSMI(dvp); 14574bff34e3Sthurlow dnp = VTOSMB(dvp); 14584bff34e3Sthurlow 1459*a19609f8Sjv ASSERT(curproc->p_zone == smi->smi_zone_ref.zref_zone); 14604bff34e3Sthurlow 14614bff34e3Sthurlow #ifdef NOT_YET 14624bff34e3Sthurlow vcp = SSTOVC(smi->smi_share); 14634bff34e3Sthurlow 14644bff34e3Sthurlow /* XXX: Should compute this once and store it in smbmntinfo_t */ 14654bff34e3Sthurlow supplen = (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) ? 255 : 12; 14664bff34e3Sthurlow #else 14674bff34e3Sthurlow supplen = 255; 14684bff34e3Sthurlow #endif 14694bff34e3Sthurlow 14704bff34e3Sthurlow /* 14714bff34e3Sthurlow * RWlock must be held, either reader or writer. 14724bff34e3Sthurlow * XXX: Can we check without looking directly 14734bff34e3Sthurlow * inside the struct smbfs_rwlock_t? 14744bff34e3Sthurlow */ 14754bff34e3Sthurlow ASSERT(dnp->r_rwlock.count != 0); 14764bff34e3Sthurlow 14774bff34e3Sthurlow /* 147802d09e03SGordon Ross * If lookup is for "", just return dvp. 147902d09e03SGordon Ross * No need to perform any access checks. 14804bff34e3Sthurlow */ 14814bff34e3Sthurlow if (nmlen == 0) { 14824bff34e3Sthurlow VN_HOLD(dvp); 14834bff34e3Sthurlow *vpp = dvp; 14844bff34e3Sthurlow return (0); 14854bff34e3Sthurlow } 14864bff34e3Sthurlow 14874bff34e3Sthurlow /* 148891d632c8Sgwr * Can't do lookups in non-directories. 14894bff34e3Sthurlow */ 14904bff34e3Sthurlow if (dvp->v_type != VDIR) 14914bff34e3Sthurlow return (ENOTDIR); 14924bff34e3Sthurlow 149391d632c8Sgwr /* 149491d632c8Sgwr * Need search permission in the directory. 149591d632c8Sgwr */ 14964bff34e3Sthurlow error = smbfs_access(dvp, VEXEC, 0, cr, ct); 14974bff34e3Sthurlow if (error) 14984bff34e3Sthurlow return (error); 14994bff34e3Sthurlow 15004bff34e3Sthurlow /* 150102d09e03SGordon Ross * If lookup is for ".", just return dvp. 150202d09e03SGordon Ross * Access check was done above. 15034bff34e3Sthurlow */ 15044bff34e3Sthurlow if (nmlen == 1 && name[0] == '.') { 15054bff34e3Sthurlow VN_HOLD(dvp); 15064bff34e3Sthurlow *vpp = dvp; 15074bff34e3Sthurlow return (0); 15084bff34e3Sthurlow } 15094bff34e3Sthurlow 15104bff34e3Sthurlow /* 151191d632c8Sgwr * Now some sanity checks on the name. 151291d632c8Sgwr * First check the length. 15134bff34e3Sthurlow */ 151491d632c8Sgwr if (nmlen > supplen) 151591d632c8Sgwr return (ENAMETOOLONG); 151691d632c8Sgwr 151791d632c8Sgwr /* 151891d632c8Sgwr * Avoid surprises with characters that are 151991d632c8Sgwr * illegal in Windows file names. 152091d632c8Sgwr * Todo: CATIA mappings XXX 152191d632c8Sgwr */ 152291d632c8Sgwr ill = illegal_chars; 152391d632c8Sgwr if (dnp->n_flag & N_XATTR) 152491d632c8Sgwr ill++; /* allow colon */ 152591d632c8Sgwr if (strpbrk(nm, ill)) 152691d632c8Sgwr return (EINVAL); 152791d632c8Sgwr 15284bff34e3Sthurlow /* 152902d09e03SGordon Ross * Special handling for lookup of ".." 15304bff34e3Sthurlow * 15314bff34e3Sthurlow * We keep full pathnames (as seen on the server) 15324bff34e3Sthurlow * so we can just trim off the last component to 15334bff34e3Sthurlow * get the full pathname of the parent. Note: 15344bff34e3Sthurlow * We don't actually copy and modify, but just 15354bff34e3Sthurlow * compute the trimmed length and pass that with 15364bff34e3Sthurlow * the current dir path (not null terminated). 15374bff34e3Sthurlow * 15384bff34e3Sthurlow * We don't go over-the-wire to get attributes 15394bff34e3Sthurlow * for ".." because we know it's a directory, 15404bff34e3Sthurlow * and we can just leave the rest "stale" 15414bff34e3Sthurlow * until someone does a getattr. 15424bff34e3Sthurlow */ 15434bff34e3Sthurlow if (nmlen == 2 && name[0] == '.' && name[1] == '.') { 15444bff34e3Sthurlow if (dvp->v_flag & VROOT) { 15454bff34e3Sthurlow /* 15464bff34e3Sthurlow * Already at the root. This can happen 15474bff34e3Sthurlow * with directory listings at the root, 15484bff34e3Sthurlow * which lookup "." and ".." to get the 15494bff34e3Sthurlow * inode numbers. Let ".." be the same 15504bff34e3Sthurlow * as "." in the FS root. 15514bff34e3Sthurlow */ 15524bff34e3Sthurlow VN_HOLD(dvp); 15534bff34e3Sthurlow *vpp = dvp; 15544bff34e3Sthurlow return (0); 15554bff34e3Sthurlow } 15564bff34e3Sthurlow 155791d632c8Sgwr /* 155891d632c8Sgwr * Special case for XATTR directory 155991d632c8Sgwr */ 156091d632c8Sgwr if (dvp->v_flag & V_XATTRDIR) { 156191d632c8Sgwr error = smbfs_xa_parent(dvp, vpp); 156291d632c8Sgwr return (error); 156391d632c8Sgwr } 156491d632c8Sgwr 15654bff34e3Sthurlow /* 15664bff34e3Sthurlow * Find the parent path length. 15674bff34e3Sthurlow */ 15684bff34e3Sthurlow rplen = dnp->n_rplen; 15694bff34e3Sthurlow ASSERT(rplen > 0); 15704bff34e3Sthurlow while (--rplen >= 0) { 15714bff34e3Sthurlow if (dnp->n_rpath[rplen] == '\\') 15724bff34e3Sthurlow break; 15734bff34e3Sthurlow } 157402d09e03SGordon Ross if (rplen <= 0) { 15754bff34e3Sthurlow /* Found our way to the root. */ 15764bff34e3Sthurlow vp = SMBTOV(smi->smi_root); 15774bff34e3Sthurlow VN_HOLD(vp); 15784bff34e3Sthurlow *vpp = vp; 15794bff34e3Sthurlow return (0); 15804bff34e3Sthurlow } 158102d09e03SGordon Ross np = smbfs_node_findcreate(smi, 158202d09e03SGordon Ross dnp->n_rpath, rplen, NULL, 0, 0, 158302d09e03SGordon Ross &smbfs_fattr0); /* force create */ 158402d09e03SGordon Ross ASSERT(np != NULL); 158502d09e03SGordon Ross vp = SMBTOV(np); 15864bff34e3Sthurlow vp->v_type = VDIR; 15874bff34e3Sthurlow 15884bff34e3Sthurlow /* Success! */ 15894bff34e3Sthurlow *vpp = vp; 15904bff34e3Sthurlow return (0); 15914bff34e3Sthurlow } 15924bff34e3Sthurlow 15934bff34e3Sthurlow /* 159402d09e03SGordon Ross * Normal lookup of a name under this directory. 159502d09e03SGordon Ross * Note we handled "", ".", ".." above. 159602d09e03SGordon Ross */ 159702d09e03SGordon Ross if (cache_ok) { 159802d09e03SGordon Ross /* 159902d09e03SGordon Ross * The caller indicated that it's OK to use a 160002d09e03SGordon Ross * cached result for this lookup, so try to 160102d09e03SGordon Ross * reclaim a node from the smbfs node cache. 160202d09e03SGordon Ross */ 160302d09e03SGordon Ross error = smbfslookup_cache(dvp, nm, nmlen, &vp, cr); 160402d09e03SGordon Ross if (error) 160502d09e03SGordon Ross return (error); 160602d09e03SGordon Ross if (vp != NULL) { 160702d09e03SGordon Ross /* hold taken in lookup_cache */ 160802d09e03SGordon Ross *vpp = vp; 160902d09e03SGordon Ross return (0); 161002d09e03SGordon Ross } 161102d09e03SGordon Ross } 161202d09e03SGordon Ross 161302d09e03SGordon Ross /* 161402d09e03SGordon Ross * OK, go over-the-wire to get the attributes, 161502d09e03SGordon Ross * then create the node. 16164bff34e3Sthurlow */ 1617613a2f6bSGordon Ross smb_credinit(&scred, cr); 16184bff34e3Sthurlow /* Note: this can allocate a new "name" */ 16194bff34e3Sthurlow error = smbfs_smb_lookup(dnp, &name, &nmlen, &fa, &scred); 16204bff34e3Sthurlow smb_credrele(&scred); 162102d09e03SGordon Ross if (error == ENOTDIR) { 162202d09e03SGordon Ross /* 162302d09e03SGordon Ross * Lookup failed because this directory was 162402d09e03SGordon Ross * removed or renamed by another client. 162502d09e03SGordon Ross * Remove any cached attributes under it. 162602d09e03SGordon Ross */ 162702d09e03SGordon Ross smbfs_attrcache_remove(dnp); 162802d09e03SGordon Ross smbfs_attrcache_prune(dnp); 162902d09e03SGordon Ross } 16304bff34e3Sthurlow if (error) 16314bff34e3Sthurlow goto out; 16324bff34e3Sthurlow 16334bff34e3Sthurlow error = smbfs_nget(dvp, name, nmlen, &fa, &vp); 16344bff34e3Sthurlow if (error) 16354bff34e3Sthurlow goto out; 16364bff34e3Sthurlow 16374bff34e3Sthurlow /* Success! */ 16384bff34e3Sthurlow *vpp = vp; 16394bff34e3Sthurlow 16404bff34e3Sthurlow out: 16414bff34e3Sthurlow /* smbfs_smb_lookup may have allocated name. */ 16424bff34e3Sthurlow if (name != nm) 16434bff34e3Sthurlow smbfs_name_free(name, nmlen); 16444bff34e3Sthurlow 16454bff34e3Sthurlow return (error); 16464bff34e3Sthurlow } 16474bff34e3Sthurlow 164802d09e03SGordon Ross /* 164902d09e03SGordon Ross * smbfslookup_cache 165002d09e03SGordon Ross * 165102d09e03SGordon Ross * Try to reclaim a node from the smbfs node cache. 165202d09e03SGordon Ross * Some statistics for DEBUG. 165302d09e03SGordon Ross * 165402d09e03SGordon Ross * This mechanism lets us avoid many of the five (or more) 165502d09e03SGordon Ross * OtW lookup calls per file seen with "ls -l" if we search 165602d09e03SGordon Ross * the smbfs node cache for recently inactive(ated) nodes. 165702d09e03SGordon Ross */ 165891d632c8Sgwr #ifdef DEBUG 165902d09e03SGordon Ross int smbfs_lookup_cache_calls = 0; 166002d09e03SGordon Ross int smbfs_lookup_cache_error = 0; 166102d09e03SGordon Ross int smbfs_lookup_cache_miss = 0; 166202d09e03SGordon Ross int smbfs_lookup_cache_stale = 0; 166302d09e03SGordon Ross int smbfs_lookup_cache_hits = 0; 166402d09e03SGordon Ross #endif /* DEBUG */ 166591d632c8Sgwr 166691d632c8Sgwr /* ARGSUSED */ 166791d632c8Sgwr static int 166802d09e03SGordon Ross smbfslookup_cache(vnode_t *dvp, char *nm, int nmlen, 166902d09e03SGordon Ross vnode_t **vpp, cred_t *cr) 167091d632c8Sgwr { 167191d632c8Sgwr struct vattr va; 167291d632c8Sgwr smbnode_t *dnp; 167302d09e03SGordon Ross smbnode_t *np; 167402d09e03SGordon Ross vnode_t *vp; 167502d09e03SGordon Ross int error; 167602d09e03SGordon Ross char sep; 167791d632c8Sgwr 167891d632c8Sgwr dnp = VTOSMB(dvp); 167902d09e03SGordon Ross *vpp = NULL; 168091d632c8Sgwr 168102d09e03SGordon Ross #ifdef DEBUG 168202d09e03SGordon Ross smbfs_lookup_cache_calls++; 168302d09e03SGordon Ross #endif 168491d632c8Sgwr 168591d632c8Sgwr /* 168602d09e03SGordon Ross * First make sure we can get attributes for the 168702d09e03SGordon Ross * directory. Cached attributes are OK here. 168802d09e03SGordon Ross * If we removed or renamed the directory, this 168902d09e03SGordon Ross * will return ENOENT. If someone else removed 169002d09e03SGordon Ross * this directory or file, we'll find out when we 169102d09e03SGordon Ross * try to open or get attributes. 169291d632c8Sgwr */ 169302d09e03SGordon Ross va.va_mask = AT_TYPE | AT_MODE; 169402d09e03SGordon Ross error = smbfsgetattr(dvp, &va, cr); 169502d09e03SGordon Ross if (error) { 169691d632c8Sgwr #ifdef DEBUG 169702d09e03SGordon Ross smbfs_lookup_cache_error++; 169891d632c8Sgwr #endif 169902d09e03SGordon Ross return (error); 170002d09e03SGordon Ross } 170102d09e03SGordon Ross 170202d09e03SGordon Ross /* 170302d09e03SGordon Ross * Passing NULL smbfattr here so we will 170402d09e03SGordon Ross * just look, not create. 170502d09e03SGordon Ross */ 170602d09e03SGordon Ross sep = SMBFS_DNP_SEP(dnp); 170702d09e03SGordon Ross np = smbfs_node_findcreate(dnp->n_mount, 170802d09e03SGordon Ross dnp->n_rpath, dnp->n_rplen, 170902d09e03SGordon Ross nm, nmlen, sep, NULL); 171002d09e03SGordon Ross if (np == NULL) { 171191d632c8Sgwr #ifdef DEBUG 171202d09e03SGordon Ross smbfs_lookup_cache_miss++; 171391d632c8Sgwr #endif 171402d09e03SGordon Ross return (0); 171502d09e03SGordon Ross } 171602d09e03SGordon Ross 171702d09e03SGordon Ross /* 171802d09e03SGordon Ross * Found it. Attributes still valid? 171902d09e03SGordon Ross */ 172002d09e03SGordon Ross vp = SMBTOV(np); 172102d09e03SGordon Ross if (np->r_attrtime <= gethrtime()) { 172202d09e03SGordon Ross /* stale */ 172391d632c8Sgwr #ifdef DEBUG 172402d09e03SGordon Ross smbfs_lookup_cache_stale++; 172591d632c8Sgwr #endif 172602d09e03SGordon Ross VN_RELE(vp); 172702d09e03SGordon Ross return (0); 172891d632c8Sgwr } 172902d09e03SGordon Ross 173002d09e03SGordon Ross /* 173102d09e03SGordon Ross * Success! 173202d09e03SGordon Ross * Caller gets hold from smbfs_node_findcreate 173302d09e03SGordon Ross */ 173491d632c8Sgwr #ifdef DEBUG 173502d09e03SGordon Ross smbfs_lookup_cache_hits++; 173691d632c8Sgwr #endif 173702d09e03SGordon Ross *vpp = vp; 173891d632c8Sgwr return (0); 173991d632c8Sgwr } 174091d632c8Sgwr 17414bff34e3Sthurlow /* 17424bff34e3Sthurlow * XXX 17434bff34e3Sthurlow * vsecattr_t is new to build 77, and we need to eventually support 17444bff34e3Sthurlow * it in order to create an ACL when an object is created. 17454bff34e3Sthurlow * 17464bff34e3Sthurlow * This op should support the new FIGNORECASE flag for case-insensitive 17474bff34e3Sthurlow * lookups, per PSARC 2007/244. 17484bff34e3Sthurlow */ 17494bff34e3Sthurlow /* ARGSUSED */ 17504bff34e3Sthurlow static int 17514bff34e3Sthurlow smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive, 17524bff34e3Sthurlow int mode, vnode_t **vpp, cred_t *cr, int lfaware, caller_context_t *ct, 17534bff34e3Sthurlow vsecattr_t *vsecp) 17544bff34e3Sthurlow { 17554bff34e3Sthurlow int error; 17564bff34e3Sthurlow int cerror; 17574bff34e3Sthurlow vfs_t *vfsp; 17584bff34e3Sthurlow vnode_t *vp; 17594bff34e3Sthurlow #ifdef NOT_YET 17604bff34e3Sthurlow smbnode_t *np; 17614bff34e3Sthurlow #endif 17624bff34e3Sthurlow smbnode_t *dnp; 17634bff34e3Sthurlow smbmntinfo_t *smi; 17644bff34e3Sthurlow struct vattr vattr; 17654bff34e3Sthurlow struct smbfattr fattr; 17664bff34e3Sthurlow struct smb_cred scred; 17674bff34e3Sthurlow const char *name = (const char *)nm; 17684bff34e3Sthurlow int nmlen = strlen(nm); 17694bff34e3Sthurlow uint32_t disp; 17704bff34e3Sthurlow uint16_t fid; 177191d632c8Sgwr int xattr; 17724bff34e3Sthurlow 17734bff34e3Sthurlow vfsp = dvp->v_vfsp; 17744bff34e3Sthurlow smi = VFTOSMI(vfsp); 17754bff34e3Sthurlow dnp = VTOSMB(dvp); 17764bff34e3Sthurlow vp = NULL; 17774bff34e3Sthurlow 1778*a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 17794bff34e3Sthurlow return (EPERM); 17804bff34e3Sthurlow 17814bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 17824bff34e3Sthurlow return (EIO); 17834bff34e3Sthurlow 17844bff34e3Sthurlow /* 17854bff34e3Sthurlow * Note: this may break mknod(2) calls to create a directory, 17864bff34e3Sthurlow * but that's obscure use. Some other filesystems do this. 17874bff34e3Sthurlow * XXX: Later, redirect VDIR type here to _mkdir. 17884bff34e3Sthurlow */ 17894bff34e3Sthurlow if (va->va_type != VREG) 17904bff34e3Sthurlow return (EINVAL); 17914bff34e3Sthurlow 17924bff34e3Sthurlow /* 17934bff34e3Sthurlow * If the pathname is "", just use dvp, no checks. 17944bff34e3Sthurlow * Do this outside of the rwlock (like zfs). 17954bff34e3Sthurlow */ 17964bff34e3Sthurlow if (nmlen == 0) { 17974bff34e3Sthurlow VN_HOLD(dvp); 17984bff34e3Sthurlow *vpp = dvp; 17994bff34e3Sthurlow return (0); 18004bff34e3Sthurlow } 18014bff34e3Sthurlow 18024bff34e3Sthurlow /* Don't allow "." or ".." through here. */ 18034bff34e3Sthurlow if ((nmlen == 1 && name[0] == '.') || 18044bff34e3Sthurlow (nmlen == 2 && name[0] == '.' && name[1] == '.')) 18054bff34e3Sthurlow return (EISDIR); 18064bff34e3Sthurlow 18074bff34e3Sthurlow /* 18084bff34e3Sthurlow * We make a copy of the attributes because the caller does not 18094bff34e3Sthurlow * expect us to change what va points to. 18104bff34e3Sthurlow */ 18114bff34e3Sthurlow vattr = *va; 18124bff34e3Sthurlow 18134bff34e3Sthurlow if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp))) 18144bff34e3Sthurlow return (EINTR); 1815613a2f6bSGordon Ross smb_credinit(&scred, cr); 18164bff34e3Sthurlow 18174bff34e3Sthurlow /* 18184bff34e3Sthurlow * XXX: Do we need r_lkserlock too? 18194bff34e3Sthurlow * No use of any shared fid or fctx... 18204bff34e3Sthurlow */ 18214bff34e3Sthurlow 18224bff34e3Sthurlow /* 18234bff34e3Sthurlow * NFS needs to go over the wire, just to be sure whether the 182402d09e03SGordon Ross * file exists or not. Using a cached result is dangerous in 18254bff34e3Sthurlow * this case when making a decision regarding existence. 18264bff34e3Sthurlow * 18274bff34e3Sthurlow * The SMB protocol does NOT really need to go OTW here 18284bff34e3Sthurlow * thanks to the expressive NTCREATE disposition values. 18294bff34e3Sthurlow * Unfortunately, to do Unix access checks correctly, 18304bff34e3Sthurlow * we need to know if the object already exists. 18314bff34e3Sthurlow * When the object does not exist, we need VWRITE on 18324bff34e3Sthurlow * the directory. Note: smbfslookup() checks VEXEC. 18334bff34e3Sthurlow */ 18344bff34e3Sthurlow error = smbfslookup(dvp, nm, &vp, cr, 0, ct); 18354bff34e3Sthurlow if (error == 0) { 18364bff34e3Sthurlow /* 183742645588SGordon Ross * The file already exists. Error? 183842645588SGordon Ross * NB: have a hold from smbfslookup 18394bff34e3Sthurlow */ 18404bff34e3Sthurlow if (exclusive == EXCL) { 18414bff34e3Sthurlow error = EEXIST; 184242645588SGordon Ross VN_RELE(vp); 18434bff34e3Sthurlow goto out; 18444bff34e3Sthurlow } 18454bff34e3Sthurlow /* 18464bff34e3Sthurlow * Verify requested access. 18474bff34e3Sthurlow */ 18484bff34e3Sthurlow error = smbfs_access(vp, mode, 0, cr, ct); 184942645588SGordon Ross if (error) { 185042645588SGordon Ross VN_RELE(vp); 18514bff34e3Sthurlow goto out; 185242645588SGordon Ross } 18534bff34e3Sthurlow 18544bff34e3Sthurlow /* 18554bff34e3Sthurlow * Truncate (if requested). 18564bff34e3Sthurlow */ 18574bff34e3Sthurlow if ((vattr.va_mask & AT_SIZE) && vattr.va_size == 0) { 18584bff34e3Sthurlow vattr.va_mask = AT_SIZE; 18594bff34e3Sthurlow error = smbfssetattr(vp, &vattr, 0, cr); 186042645588SGordon Ross if (error) { 186142645588SGordon Ross VN_RELE(vp); 18624bff34e3Sthurlow goto out; 186342645588SGordon Ross } 18644bff34e3Sthurlow } 18654bff34e3Sthurlow /* Success! */ 18664bff34e3Sthurlow #ifdef NOT_YET 18674bff34e3Sthurlow vnevent_create(vp, ct); 18684bff34e3Sthurlow #endif 18694bff34e3Sthurlow *vpp = vp; 18704bff34e3Sthurlow goto out; 18714bff34e3Sthurlow } 18724bff34e3Sthurlow 18734bff34e3Sthurlow /* 18744bff34e3Sthurlow * The file did not exist. Need VWRITE in the directory. 18754bff34e3Sthurlow */ 18764bff34e3Sthurlow error = smbfs_access(dvp, VWRITE, 0, cr, ct); 18774bff34e3Sthurlow if (error) 18784bff34e3Sthurlow goto out; 18794bff34e3Sthurlow 18804bff34e3Sthurlow /* 18814bff34e3Sthurlow * Now things get tricky. We also need to check the 18824bff34e3Sthurlow * requested open mode against the file we may create. 18834bff34e3Sthurlow * See comments at smbfs_access_rwx 18844bff34e3Sthurlow */ 18854bff34e3Sthurlow error = smbfs_access_rwx(vfsp, VREG, mode, cr); 18864bff34e3Sthurlow if (error) 18874bff34e3Sthurlow goto out; 18884bff34e3Sthurlow 18894bff34e3Sthurlow /* 18904bff34e3Sthurlow * Now the code derived from Darwin, 18914bff34e3Sthurlow * but with greater use of NT_CREATE 18924bff34e3Sthurlow * disposition options. Much changed. 18934bff34e3Sthurlow * 18944bff34e3Sthurlow * Create (or open) a new child node. 18954bff34e3Sthurlow * Note we handled "." and ".." above. 18964bff34e3Sthurlow */ 18974bff34e3Sthurlow 18984bff34e3Sthurlow if (exclusive == EXCL) 18994bff34e3Sthurlow disp = NTCREATEX_DISP_CREATE; 19004bff34e3Sthurlow else { 19014bff34e3Sthurlow /* Truncate regular files if requested. */ 19024bff34e3Sthurlow if ((va->va_type == VREG) && 19034bff34e3Sthurlow (va->va_mask & AT_SIZE) && 19044bff34e3Sthurlow (va->va_size == 0)) 19054bff34e3Sthurlow disp = NTCREATEX_DISP_OVERWRITE_IF; 19064bff34e3Sthurlow else 19074bff34e3Sthurlow disp = NTCREATEX_DISP_OPEN_IF; 19084bff34e3Sthurlow } 190991d632c8Sgwr xattr = (dnp->n_flag & N_XATTR) ? 1 : 0; 191002d09e03SGordon Ross error = smbfs_smb_create(dnp, 191102d09e03SGordon Ross name, nmlen, xattr, 191202d09e03SGordon Ross disp, &scred, &fid); 19134bff34e3Sthurlow if (error) 19144bff34e3Sthurlow goto out; 19154bff34e3Sthurlow 19164bff34e3Sthurlow /* 19174bff34e3Sthurlow * XXX: Missing some code here to deal with 19184bff34e3Sthurlow * the case where we opened an existing file, 19194bff34e3Sthurlow * it's size is larger than 32-bits, and we're 19204bff34e3Sthurlow * setting the size from a process that's not 19214bff34e3Sthurlow * aware of large file offsets. i.e. 19224bff34e3Sthurlow * from the NFS3 code: 19234bff34e3Sthurlow */ 19244bff34e3Sthurlow #if NOT_YET /* XXX */ 19254bff34e3Sthurlow if ((vattr.va_mask & AT_SIZE) && 19264bff34e3Sthurlow vp->v_type == VREG) { 19274bff34e3Sthurlow np = VTOSMB(vp); 19284bff34e3Sthurlow /* 19294bff34e3Sthurlow * Check here for large file handled 19304bff34e3Sthurlow * by LF-unaware process (as 19314bff34e3Sthurlow * ufs_create() does) 19324bff34e3Sthurlow */ 19334bff34e3Sthurlow if (!(lfaware & FOFFMAX)) { 19344bff34e3Sthurlow mutex_enter(&np->r_statelock); 19354bff34e3Sthurlow if (np->r_size > MAXOFF32_T) 19364bff34e3Sthurlow error = EOVERFLOW; 19374bff34e3Sthurlow mutex_exit(&np->r_statelock); 19384bff34e3Sthurlow } 19394bff34e3Sthurlow if (!error) { 19404bff34e3Sthurlow vattr.va_mask = AT_SIZE; 19414bff34e3Sthurlow error = smbfssetattr(vp, 19424bff34e3Sthurlow &vattr, 0, cr); 19434bff34e3Sthurlow } 19444bff34e3Sthurlow } 19454bff34e3Sthurlow #endif /* XXX */ 19464bff34e3Sthurlow /* 19474bff34e3Sthurlow * Should use the fid to get/set the size 19484bff34e3Sthurlow * while we have it opened here. See above. 19494bff34e3Sthurlow */ 19504bff34e3Sthurlow 19514bff34e3Sthurlow cerror = smbfs_smb_close(smi->smi_share, fid, NULL, &scred); 19524bff34e3Sthurlow if (cerror) 195302d09e03SGordon Ross SMBVDEBUG("error %d closing %s\\%s\n", 19544bff34e3Sthurlow cerror, dnp->n_rpath, name); 19554bff34e3Sthurlow 19564bff34e3Sthurlow /* 19574bff34e3Sthurlow * In the open case, the name may differ a little 19584bff34e3Sthurlow * from what we passed to create (case, etc.) 19594bff34e3Sthurlow * so call lookup to get the (opened) name. 19604bff34e3Sthurlow * 19614bff34e3Sthurlow * XXX: Could avoid this extra lookup if the 19624bff34e3Sthurlow * "createact" result from NT_CREATE says we 19634bff34e3Sthurlow * created the object. 19644bff34e3Sthurlow */ 19654bff34e3Sthurlow error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred); 19664bff34e3Sthurlow if (error) 19674bff34e3Sthurlow goto out; 19684bff34e3Sthurlow 19694bff34e3Sthurlow /* update attr and directory cache */ 19704bff34e3Sthurlow smbfs_attr_touchdir(dnp); 19714bff34e3Sthurlow 19724bff34e3Sthurlow error = smbfs_nget(dvp, name, nmlen, &fattr, &vp); 19734bff34e3Sthurlow if (error) 19744bff34e3Sthurlow goto out; 19754bff34e3Sthurlow 197691d632c8Sgwr /* XXX invalidate pages if we truncated? */ 197791d632c8Sgwr 19784bff34e3Sthurlow /* Success! */ 19794bff34e3Sthurlow *vpp = vp; 19804bff34e3Sthurlow error = 0; 19814bff34e3Sthurlow 19824bff34e3Sthurlow out: 19834bff34e3Sthurlow smb_credrele(&scred); 198402d09e03SGordon Ross smbfs_rw_exit(&dnp->r_rwlock); 19854bff34e3Sthurlow if (name != nm) 19864bff34e3Sthurlow smbfs_name_free(name, nmlen); 19874bff34e3Sthurlow return (error); 19884bff34e3Sthurlow } 19894bff34e3Sthurlow 19904bff34e3Sthurlow /* 19914bff34e3Sthurlow * XXX 19924bff34e3Sthurlow * This op should support the new FIGNORECASE flag for case-insensitive 19934bff34e3Sthurlow * lookups, per PSARC 2007/244. 19944bff34e3Sthurlow */ 19954bff34e3Sthurlow /* ARGSUSED */ 19964bff34e3Sthurlow static int 19974bff34e3Sthurlow smbfs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct, 19984bff34e3Sthurlow int flags) 19994bff34e3Sthurlow { 20004bff34e3Sthurlow int error; 20014bff34e3Sthurlow vnode_t *vp; 20024bff34e3Sthurlow smbnode_t *np; 20034bff34e3Sthurlow smbnode_t *dnp; 20044bff34e3Sthurlow struct smb_cred scred; 20054bff34e3Sthurlow /* enum smbfsstat status; */ 20064bff34e3Sthurlow smbmntinfo_t *smi; 20074bff34e3Sthurlow 20084bff34e3Sthurlow smi = VTOSMI(dvp); 20094bff34e3Sthurlow 2010*a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 20114bff34e3Sthurlow return (EPERM); 20124bff34e3Sthurlow 20134bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 20144bff34e3Sthurlow return (EIO); 20154bff34e3Sthurlow 20164bff34e3Sthurlow dnp = VTOSMB(dvp); 20174bff34e3Sthurlow if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp))) 20184bff34e3Sthurlow return (EINTR); 201902d09e03SGordon Ross smb_credinit(&scred, cr); 20204bff34e3Sthurlow 20214bff34e3Sthurlow /* 20224bff34e3Sthurlow * Verify access to the dirctory. 20234bff34e3Sthurlow */ 20244bff34e3Sthurlow error = smbfs_access(dvp, VWRITE|VEXEC, 0, cr, ct); 20254bff34e3Sthurlow if (error) 20264bff34e3Sthurlow goto out; 20274bff34e3Sthurlow 20284bff34e3Sthurlow /* 20294bff34e3Sthurlow * NOTE: the darwin code gets the "vp" passed in so it looks 20304bff34e3Sthurlow * like the "vp" has probably been "lookup"ed by the VFS layer. 20314bff34e3Sthurlow * It looks like we will need to lookup the vp to check the 20324bff34e3Sthurlow * caches and check if the object being deleted is a directory. 20334bff34e3Sthurlow */ 20344bff34e3Sthurlow error = smbfslookup(dvp, nm, &vp, cr, 0, ct); 20354bff34e3Sthurlow if (error) 20364bff34e3Sthurlow goto out; 20374bff34e3Sthurlow 20384bff34e3Sthurlow /* Never allow link/unlink directories on CIFS. */ 20394bff34e3Sthurlow if (vp->v_type == VDIR) { 20404bff34e3Sthurlow VN_RELE(vp); 20414bff34e3Sthurlow error = EPERM; 20424bff34e3Sthurlow goto out; 20434bff34e3Sthurlow } 20444bff34e3Sthurlow 20454bff34e3Sthurlow /* 20464bff34e3Sthurlow * Now we have the real reference count on the vnode 204702d09e03SGordon Ross * Do we have the file open? 20484bff34e3Sthurlow */ 20494bff34e3Sthurlow np = VTOSMB(vp); 20504bff34e3Sthurlow mutex_enter(&np->r_statelock); 205102d09e03SGordon Ross if ((vp->v_count > 1) && (np->n_fidrefs > 0)) { 20524bff34e3Sthurlow /* 20534bff34e3Sthurlow * NFS does a rename on remove here. 20544bff34e3Sthurlow * Probably not applicable for SMB. 20554bff34e3Sthurlow * Like Darwin, just return EBUSY. 20564bff34e3Sthurlow * 205702d09e03SGordon Ross * XXX: Todo - Use Trans2rename, and 205802d09e03SGordon Ross * if that fails, ask the server to 20594bff34e3Sthurlow * set the delete-on-close flag. 20604bff34e3Sthurlow */ 20614bff34e3Sthurlow mutex_exit(&np->r_statelock); 20624bff34e3Sthurlow error = EBUSY; 20634bff34e3Sthurlow } else { 206402d09e03SGordon Ross smbfs_attrcache_rm_locked(np); 20654bff34e3Sthurlow mutex_exit(&np->r_statelock); 20664bff34e3Sthurlow 20674bff34e3Sthurlow error = smbfs_smb_delete(np, &scred, NULL, 0, 0); 20684bff34e3Sthurlow 206902d09e03SGordon Ross /* 207002d09e03SGordon Ross * If the file should no longer exist, discard 207102d09e03SGordon Ross * any cached attributes under this node. 207202d09e03SGordon Ross */ 207302d09e03SGordon Ross switch (error) { 207402d09e03SGordon Ross case 0: 207502d09e03SGordon Ross case ENOENT: 207602d09e03SGordon Ross case ENOTDIR: 207702d09e03SGordon Ross smbfs_attrcache_prune(np); 207802d09e03SGordon Ross break; 207902d09e03SGordon Ross } 20804bff34e3Sthurlow } 20814bff34e3Sthurlow 20824bff34e3Sthurlow VN_RELE(vp); 20834bff34e3Sthurlow 20844bff34e3Sthurlow out: 208502d09e03SGordon Ross smb_credrele(&scred); 20864bff34e3Sthurlow smbfs_rw_exit(&dnp->r_rwlock); 20874bff34e3Sthurlow 20884bff34e3Sthurlow return (error); 20894bff34e3Sthurlow } 20904bff34e3Sthurlow 20914bff34e3Sthurlow 20924bff34e3Sthurlow /* 20934bff34e3Sthurlow * XXX 20944bff34e3Sthurlow * This op should support the new FIGNORECASE flag for case-insensitive 20954bff34e3Sthurlow * lookups, per PSARC 2007/244. 20964bff34e3Sthurlow */ 20974bff34e3Sthurlow /* ARGSUSED */ 20984bff34e3Sthurlow static int 20994bff34e3Sthurlow smbfs_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr, 21004bff34e3Sthurlow caller_context_t *ct, int flags) 21014bff34e3Sthurlow { 21024bff34e3Sthurlow /* vnode_t *realvp; */ 21034bff34e3Sthurlow 2104*a19609f8Sjv if (curproc->p_zone != VTOSMI(odvp)->smi_zone_ref.zref_zone || 2105*a19609f8Sjv curproc->p_zone != VTOSMI(ndvp)->smi_zone_ref.zref_zone) 21064bff34e3Sthurlow return (EPERM); 21074bff34e3Sthurlow 21084bff34e3Sthurlow if (VTOSMI(odvp)->smi_flags & SMI_DEAD || 21094bff34e3Sthurlow VTOSMI(ndvp)->smi_flags & SMI_DEAD || 21104bff34e3Sthurlow odvp->v_vfsp->vfs_flag & VFS_UNMOUNTED || 21114bff34e3Sthurlow ndvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 21124bff34e3Sthurlow return (EIO); 21134bff34e3Sthurlow 21144bff34e3Sthurlow return (smbfsrename(odvp, onm, ndvp, nnm, cr, ct)); 21154bff34e3Sthurlow } 21164bff34e3Sthurlow 21174bff34e3Sthurlow /* 21184bff34e3Sthurlow * smbfsrename does the real work of renaming in SMBFS 21194bff34e3Sthurlow */ 21204bff34e3Sthurlow /* ARGSUSED */ 21214bff34e3Sthurlow static int 21224bff34e3Sthurlow smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr, 21234bff34e3Sthurlow caller_context_t *ct) 21244bff34e3Sthurlow { 21254bff34e3Sthurlow int error; 21264bff34e3Sthurlow int nvp_locked = 0; 21274bff34e3Sthurlow vnode_t *nvp = NULL; 21284bff34e3Sthurlow vnode_t *ovp = NULL; 21294bff34e3Sthurlow smbnode_t *onp; 213091d632c8Sgwr smbnode_t *nnp; 21314bff34e3Sthurlow smbnode_t *odnp; 21324bff34e3Sthurlow smbnode_t *ndnp; 21334bff34e3Sthurlow struct smb_cred scred; 21344bff34e3Sthurlow /* enum smbfsstat status; */ 21354bff34e3Sthurlow 2136*a19609f8Sjv ASSERT(curproc->p_zone == VTOSMI(odvp)->smi_zone_ref.zref_zone); 21374bff34e3Sthurlow 21384bff34e3Sthurlow if (strcmp(onm, ".") == 0 || strcmp(onm, "..") == 0 || 21394bff34e3Sthurlow strcmp(nnm, ".") == 0 || strcmp(nnm, "..") == 0) 21404bff34e3Sthurlow return (EINVAL); 21414bff34e3Sthurlow 21424bff34e3Sthurlow /* 21434bff34e3Sthurlow * Check that everything is on the same filesystem. 21444bff34e3Sthurlow * vn_rename checks the fsid's, but in case we don't 21454bff34e3Sthurlow * fill those in correctly, check here too. 21464bff34e3Sthurlow */ 21474bff34e3Sthurlow if (odvp->v_vfsp != ndvp->v_vfsp) 21484bff34e3Sthurlow return (EXDEV); 21494bff34e3Sthurlow 21504bff34e3Sthurlow odnp = VTOSMB(odvp); 21514bff34e3Sthurlow ndnp = VTOSMB(ndvp); 21524bff34e3Sthurlow 21534bff34e3Sthurlow /* 21544bff34e3Sthurlow * Avoid deadlock here on old vs new directory nodes 21554bff34e3Sthurlow * by always taking the locks in order of address. 21564bff34e3Sthurlow * The order is arbitrary, but must be consistent. 21574bff34e3Sthurlow */ 21584bff34e3Sthurlow if (odnp < ndnp) { 21594bff34e3Sthurlow if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER, 21604bff34e3Sthurlow SMBINTR(odvp))) 21614bff34e3Sthurlow return (EINTR); 21624bff34e3Sthurlow if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER, 21634bff34e3Sthurlow SMBINTR(ndvp))) { 21644bff34e3Sthurlow smbfs_rw_exit(&odnp->r_rwlock); 21654bff34e3Sthurlow return (EINTR); 21664bff34e3Sthurlow } 21674bff34e3Sthurlow } else { 21684bff34e3Sthurlow if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER, 21694bff34e3Sthurlow SMBINTR(ndvp))) 21704bff34e3Sthurlow return (EINTR); 21714bff34e3Sthurlow if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER, 21724bff34e3Sthurlow SMBINTR(odvp))) { 21734bff34e3Sthurlow smbfs_rw_exit(&ndnp->r_rwlock); 21744bff34e3Sthurlow return (EINTR); 21754bff34e3Sthurlow } 21764bff34e3Sthurlow } 217702d09e03SGordon Ross smb_credinit(&scred, cr); 21784bff34e3Sthurlow /* 21794bff34e3Sthurlow * No returns after this point (goto out) 21804bff34e3Sthurlow */ 21814bff34e3Sthurlow 21824bff34e3Sthurlow /* 21834bff34e3Sthurlow * Need write access on source and target. 21844bff34e3Sthurlow * Server takes care of most checks. 21854bff34e3Sthurlow */ 21864bff34e3Sthurlow error = smbfs_access(odvp, VWRITE|VEXEC, 0, cr, ct); 21874bff34e3Sthurlow if (error) 21884bff34e3Sthurlow goto out; 21894bff34e3Sthurlow if (odvp != ndvp) { 21904bff34e3Sthurlow error = smbfs_access(ndvp, VWRITE, 0, cr, ct); 21914bff34e3Sthurlow if (error) 21924bff34e3Sthurlow goto out; 21934bff34e3Sthurlow } 21944bff34e3Sthurlow 21954bff34e3Sthurlow /* 21964bff34e3Sthurlow * Lookup the source name. Must already exist. 21974bff34e3Sthurlow */ 21984bff34e3Sthurlow error = smbfslookup(odvp, onm, &ovp, cr, 0, ct); 21994bff34e3Sthurlow if (error) 22004bff34e3Sthurlow goto out; 22014bff34e3Sthurlow 22024bff34e3Sthurlow /* 22034bff34e3Sthurlow * Lookup the target file. If it exists, it needs to be 22044bff34e3Sthurlow * checked to see whether it is a mount point and whether 22054bff34e3Sthurlow * it is active (open). 22064bff34e3Sthurlow */ 22074bff34e3Sthurlow error = smbfslookup(ndvp, nnm, &nvp, cr, 0, ct); 22084bff34e3Sthurlow if (!error) { 22094bff34e3Sthurlow /* 22104bff34e3Sthurlow * Target (nvp) already exists. Check that it 22114bff34e3Sthurlow * has the same type as the source. The server 22124bff34e3Sthurlow * will check this also, (and more reliably) but 22134bff34e3Sthurlow * this lets us return the correct error codes. 22144bff34e3Sthurlow */ 22154bff34e3Sthurlow if (ovp->v_type == VDIR) { 22164bff34e3Sthurlow if (nvp->v_type != VDIR) { 22174bff34e3Sthurlow error = ENOTDIR; 22184bff34e3Sthurlow goto out; 22194bff34e3Sthurlow } 22204bff34e3Sthurlow } else { 22214bff34e3Sthurlow if (nvp->v_type == VDIR) { 22224bff34e3Sthurlow error = EISDIR; 22234bff34e3Sthurlow goto out; 22244bff34e3Sthurlow } 22254bff34e3Sthurlow } 22264bff34e3Sthurlow 22274bff34e3Sthurlow /* 22284bff34e3Sthurlow * POSIX dictates that when the source and target 22294bff34e3Sthurlow * entries refer to the same file object, rename 22304bff34e3Sthurlow * must do nothing and exit without error. 22314bff34e3Sthurlow */ 22324bff34e3Sthurlow if (ovp == nvp) { 22334bff34e3Sthurlow error = 0; 22344bff34e3Sthurlow goto out; 22354bff34e3Sthurlow } 22364bff34e3Sthurlow 22374bff34e3Sthurlow /* 22384bff34e3Sthurlow * Also must ensure the target is not a mount point, 22394bff34e3Sthurlow * and keep mount/umount away until we're done. 22404bff34e3Sthurlow */ 22414bff34e3Sthurlow if (vn_vfsrlock(nvp)) { 22424bff34e3Sthurlow error = EBUSY; 22434bff34e3Sthurlow goto out; 22444bff34e3Sthurlow } 22454bff34e3Sthurlow nvp_locked = 1; 22464bff34e3Sthurlow if (vn_mountedvfs(nvp) != NULL) { 22474bff34e3Sthurlow error = EBUSY; 22484bff34e3Sthurlow goto out; 22494bff34e3Sthurlow } 22504bff34e3Sthurlow 225191d632c8Sgwr /* 225291d632c8Sgwr * CIFS gives a SHARING_VIOLATION error when 225391d632c8Sgwr * trying to rename onto an exising object, 225491d632c8Sgwr * so try to remove the target first. 225591d632c8Sgwr * (Only for files, not directories.) 225691d632c8Sgwr */ 225791d632c8Sgwr if (nvp->v_type == VDIR) { 225891d632c8Sgwr error = EEXIST; 225991d632c8Sgwr goto out; 226091d632c8Sgwr } 22614bff34e3Sthurlow 226291d632c8Sgwr /* 226342645588SGordon Ross * Nodes that are "not active" here have v_count=2 226442645588SGordon Ross * because vn_renameat (our caller) did a lookup on 226542645588SGordon Ross * both the source and target before this call. 226642645588SGordon Ross * Otherwise this similar to smbfs_remove. 226791d632c8Sgwr */ 226891d632c8Sgwr nnp = VTOSMB(nvp); 226991d632c8Sgwr mutex_enter(&nnp->r_statelock); 227002d09e03SGordon Ross if ((nvp->v_count > 2) && (nnp->n_fidrefs > 0)) { 22714bff34e3Sthurlow /* 22724bff34e3Sthurlow * The target file exists, is not the same as 22734bff34e3Sthurlow * the source file, and is active. Other FS 22744bff34e3Sthurlow * implementations unlink the target here. 22754bff34e3Sthurlow * For SMB, we don't assume we can remove an 22764bff34e3Sthurlow * open file. Return an error instead. 22774bff34e3Sthurlow */ 227891d632c8Sgwr mutex_exit(&nnp->r_statelock); 227991d632c8Sgwr error = EBUSY; 22804bff34e3Sthurlow goto out; 22814bff34e3Sthurlow } 228291d632c8Sgwr 228391d632c8Sgwr /* 228491d632c8Sgwr * Target file is not active. Try to remove it. 228591d632c8Sgwr */ 228602d09e03SGordon Ross smbfs_attrcache_rm_locked(nnp); 228702d09e03SGordon Ross mutex_exit(&nnp->r_statelock); 228802d09e03SGordon Ross 228991d632c8Sgwr error = smbfs_smb_delete(nnp, &scred, NULL, 0, 0); 229002d09e03SGordon Ross 229102d09e03SGordon Ross /* 229202d09e03SGordon Ross * Similar to smbfs_remove 229302d09e03SGordon Ross */ 229402d09e03SGordon Ross switch (error) { 229502d09e03SGordon Ross case 0: 229602d09e03SGordon Ross case ENOENT: 229702d09e03SGordon Ross case ENOTDIR: 229802d09e03SGordon Ross smbfs_attrcache_prune(nnp); 229902d09e03SGordon Ross break; 230002d09e03SGordon Ross } 230102d09e03SGordon Ross 230291d632c8Sgwr if (error) 230391d632c8Sgwr goto out; 230491d632c8Sgwr /* 230591d632c8Sgwr * OK, removed the target file. Continue as if 230691d632c8Sgwr * lookup target had failed (nvp == NULL). 230791d632c8Sgwr */ 230891d632c8Sgwr vn_vfsunlock(nvp); 230991d632c8Sgwr nvp_locked = 0; 231091d632c8Sgwr VN_RELE(nvp); 231191d632c8Sgwr nvp = NULL; 23124bff34e3Sthurlow } /* nvp */ 23134bff34e3Sthurlow 23144bff34e3Sthurlow onp = VTOSMB(ovp); 231502d09e03SGordon Ross smbfs_attrcache_remove(onp); 231602d09e03SGordon Ross 23174bff34e3Sthurlow error = smbfs_smb_rename(onp, ndnp, nnm, strlen(nnm), &scred); 23184bff34e3Sthurlow 231902d09e03SGordon Ross /* 232002d09e03SGordon Ross * If the old name should no longer exist, 232102d09e03SGordon Ross * discard any cached attributes under it. 232202d09e03SGordon Ross */ 232302d09e03SGordon Ross if (error == 0) 232402d09e03SGordon Ross smbfs_attrcache_prune(onp); 23254bff34e3Sthurlow 23264bff34e3Sthurlow out: 23274bff34e3Sthurlow if (nvp) { 23284bff34e3Sthurlow if (nvp_locked) 23294bff34e3Sthurlow vn_vfsunlock(nvp); 23304bff34e3Sthurlow VN_RELE(nvp); 23314bff34e3Sthurlow } 23324bff34e3Sthurlow if (ovp) 23334bff34e3Sthurlow VN_RELE(ovp); 23344bff34e3Sthurlow 233502d09e03SGordon Ross smb_credrele(&scred); 23364bff34e3Sthurlow smbfs_rw_exit(&odnp->r_rwlock); 23374bff34e3Sthurlow smbfs_rw_exit(&ndnp->r_rwlock); 23384bff34e3Sthurlow 23394bff34e3Sthurlow return (error); 23404bff34e3Sthurlow } 23414bff34e3Sthurlow 23424bff34e3Sthurlow /* 23434bff34e3Sthurlow * XXX 23444bff34e3Sthurlow * vsecattr_t is new to build 77, and we need to eventually support 23454bff34e3Sthurlow * it in order to create an ACL when an object is created. 23464bff34e3Sthurlow * 23474bff34e3Sthurlow * This op should support the new FIGNORECASE flag for case-insensitive 23484bff34e3Sthurlow * lookups, per PSARC 2007/244. 23494bff34e3Sthurlow */ 23504bff34e3Sthurlow /* ARGSUSED */ 23514bff34e3Sthurlow static int 23524bff34e3Sthurlow smbfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp, 23534bff34e3Sthurlow cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp) 23544bff34e3Sthurlow { 23554bff34e3Sthurlow vnode_t *vp; 23564bff34e3Sthurlow struct smbnode *dnp = VTOSMB(dvp); 23574bff34e3Sthurlow struct smbmntinfo *smi = VTOSMI(dvp); 23584bff34e3Sthurlow struct smb_cred scred; 23594bff34e3Sthurlow struct smbfattr fattr; 23604bff34e3Sthurlow const char *name = (const char *) nm; 23614bff34e3Sthurlow int nmlen = strlen(name); 23624bff34e3Sthurlow int error, hiderr; 23634bff34e3Sthurlow 2364*a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 23654bff34e3Sthurlow return (EPERM); 23664bff34e3Sthurlow 23674bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 23684bff34e3Sthurlow return (EIO); 23694bff34e3Sthurlow 23704bff34e3Sthurlow if ((nmlen == 1 && name[0] == '.') || 23714bff34e3Sthurlow (nmlen == 2 && name[0] == '.' && name[1] == '.')) 23724bff34e3Sthurlow return (EEXIST); 23734bff34e3Sthurlow 237491d632c8Sgwr /* Only plain files are allowed in V_XATTRDIR. */ 237591d632c8Sgwr if (dvp->v_flag & V_XATTRDIR) 237691d632c8Sgwr return (EINVAL); 237791d632c8Sgwr 23784bff34e3Sthurlow if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp))) 23794bff34e3Sthurlow return (EINTR); 2380613a2f6bSGordon Ross smb_credinit(&scred, cr); 23814bff34e3Sthurlow 23824bff34e3Sthurlow /* 23834bff34e3Sthurlow * XXX: Do we need r_lkserlock too? 23844bff34e3Sthurlow * No use of any shared fid or fctx... 23854bff34e3Sthurlow */ 23864bff34e3Sthurlow 23874bff34e3Sthurlow /* 23884bff34e3Sthurlow * Require write access in the containing directory. 23894bff34e3Sthurlow */ 23904bff34e3Sthurlow error = smbfs_access(dvp, VWRITE, 0, cr, ct); 23914bff34e3Sthurlow if (error) 23924bff34e3Sthurlow goto out; 23934bff34e3Sthurlow 23944bff34e3Sthurlow error = smbfs_smb_mkdir(dnp, name, nmlen, &scred); 23954bff34e3Sthurlow if (error) 23964bff34e3Sthurlow goto out; 23974bff34e3Sthurlow 23984bff34e3Sthurlow error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred); 23994bff34e3Sthurlow if (error) 24004bff34e3Sthurlow goto out; 24014bff34e3Sthurlow 24024bff34e3Sthurlow smbfs_attr_touchdir(dnp); 24034bff34e3Sthurlow 24044bff34e3Sthurlow error = smbfs_nget(dvp, name, nmlen, &fattr, &vp); 24054bff34e3Sthurlow if (error) 24064bff34e3Sthurlow goto out; 24074bff34e3Sthurlow 24084bff34e3Sthurlow if (name[0] == '.') 24094bff34e3Sthurlow if ((hiderr = smbfs_smb_hideit(VTOSMB(vp), NULL, 0, &scred))) 24104bff34e3Sthurlow SMBVDEBUG("hide failure %d\n", hiderr); 24114bff34e3Sthurlow 24124bff34e3Sthurlow /* Success! */ 24134bff34e3Sthurlow *vpp = vp; 24144bff34e3Sthurlow error = 0; 24154bff34e3Sthurlow out: 24164bff34e3Sthurlow smb_credrele(&scred); 24174bff34e3Sthurlow smbfs_rw_exit(&dnp->r_rwlock); 24184bff34e3Sthurlow 24194bff34e3Sthurlow if (name != nm) 24204bff34e3Sthurlow smbfs_name_free(name, nmlen); 24214bff34e3Sthurlow 24224bff34e3Sthurlow return (error); 24234bff34e3Sthurlow } 24244bff34e3Sthurlow 24254bff34e3Sthurlow /* 24264bff34e3Sthurlow * XXX 24274bff34e3Sthurlow * This op should support the new FIGNORECASE flag for case-insensitive 24284bff34e3Sthurlow * lookups, per PSARC 2007/244. 24294bff34e3Sthurlow */ 24304bff34e3Sthurlow /* ARGSUSED */ 24314bff34e3Sthurlow static int 24324bff34e3Sthurlow smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr, 24334bff34e3Sthurlow caller_context_t *ct, int flags) 24344bff34e3Sthurlow { 24354bff34e3Sthurlow vnode_t *vp = NULL; 24364bff34e3Sthurlow int vp_locked = 0; 24374bff34e3Sthurlow struct smbmntinfo *smi = VTOSMI(dvp); 24384bff34e3Sthurlow struct smbnode *dnp = VTOSMB(dvp); 24394bff34e3Sthurlow struct smbnode *np; 24404bff34e3Sthurlow struct smb_cred scred; 24414bff34e3Sthurlow int error; 24424bff34e3Sthurlow 2443*a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 24444bff34e3Sthurlow return (EPERM); 24454bff34e3Sthurlow 24464bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 24474bff34e3Sthurlow return (EIO); 24484bff34e3Sthurlow 24494bff34e3Sthurlow if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp))) 24504bff34e3Sthurlow return (EINTR); 2451613a2f6bSGordon Ross smb_credinit(&scred, cr); 24524bff34e3Sthurlow 24534bff34e3Sthurlow /* 24544bff34e3Sthurlow * Require w/x access in the containing directory. 24554bff34e3Sthurlow * Server handles all other access checks. 24564bff34e3Sthurlow */ 24574bff34e3Sthurlow error = smbfs_access(dvp, VEXEC|VWRITE, 0, cr, ct); 24584bff34e3Sthurlow if (error) 24594bff34e3Sthurlow goto out; 24604bff34e3Sthurlow 24614bff34e3Sthurlow /* 24624bff34e3Sthurlow * First lookup the entry to be removed. 24634bff34e3Sthurlow */ 24644bff34e3Sthurlow error = smbfslookup(dvp, nm, &vp, cr, 0, ct); 24654bff34e3Sthurlow if (error) 24664bff34e3Sthurlow goto out; 24674bff34e3Sthurlow np = VTOSMB(vp); 24684bff34e3Sthurlow 24694bff34e3Sthurlow /* 24704bff34e3Sthurlow * Disallow rmdir of "." or current dir, or the FS root. 24714bff34e3Sthurlow * Also make sure it's a directory, not a mount point, 24724bff34e3Sthurlow * and lock to keep mount/umount away until we're done. 24734bff34e3Sthurlow */ 24744bff34e3Sthurlow if ((vp == dvp) || (vp == cdir) || (vp->v_flag & VROOT)) { 24754bff34e3Sthurlow error = EINVAL; 24764bff34e3Sthurlow goto out; 24774bff34e3Sthurlow } 24784bff34e3Sthurlow if (vp->v_type != VDIR) { 24794bff34e3Sthurlow error = ENOTDIR; 24804bff34e3Sthurlow goto out; 24814bff34e3Sthurlow } 24824bff34e3Sthurlow if (vn_vfsrlock(vp)) { 24834bff34e3Sthurlow error = EBUSY; 24844bff34e3Sthurlow goto out; 24854bff34e3Sthurlow } 24864bff34e3Sthurlow vp_locked = 1; 24874bff34e3Sthurlow if (vn_mountedvfs(vp) != NULL) { 24884bff34e3Sthurlow error = EBUSY; 24894bff34e3Sthurlow goto out; 24904bff34e3Sthurlow } 24914bff34e3Sthurlow 249202d09e03SGordon Ross smbfs_attrcache_remove(np); 249302d09e03SGordon Ross error = smbfs_smb_rmdir(np, &scred); 249491d632c8Sgwr 249591d632c8Sgwr /* 249602d09e03SGordon Ross * Similar to smbfs_remove 249791d632c8Sgwr */ 249802d09e03SGordon Ross switch (error) { 249902d09e03SGordon Ross case 0: 250002d09e03SGordon Ross case ENOENT: 250102d09e03SGordon Ross case ENOTDIR: 250202d09e03SGordon Ross smbfs_attrcache_prune(np); 250302d09e03SGordon Ross break; 250491d632c8Sgwr } 250591d632c8Sgwr 25064bff34e3Sthurlow if (error) 25074bff34e3Sthurlow goto out; 25084bff34e3Sthurlow 25094bff34e3Sthurlow mutex_enter(&np->r_statelock); 25104bff34e3Sthurlow dnp->n_flag |= NMODIFIED; 25114bff34e3Sthurlow mutex_exit(&np->r_statelock); 25124bff34e3Sthurlow smbfs_attr_touchdir(dnp); 251302d09e03SGordon Ross smbfs_rmhash(np); 25144bff34e3Sthurlow 25154bff34e3Sthurlow out: 25164bff34e3Sthurlow if (vp) { 25174bff34e3Sthurlow if (vp_locked) 25184bff34e3Sthurlow vn_vfsunlock(vp); 25194bff34e3Sthurlow VN_RELE(vp); 25204bff34e3Sthurlow } 25214bff34e3Sthurlow smb_credrele(&scred); 25224bff34e3Sthurlow smbfs_rw_exit(&dnp->r_rwlock); 25234bff34e3Sthurlow 25244bff34e3Sthurlow return (error); 25254bff34e3Sthurlow } 25264bff34e3Sthurlow 25274bff34e3Sthurlow 25284bff34e3Sthurlow /* ARGSUSED */ 25294bff34e3Sthurlow static int 25304bff34e3Sthurlow smbfs_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp, 25314bff34e3Sthurlow caller_context_t *ct, int flags) 25324bff34e3Sthurlow { 25334bff34e3Sthurlow struct smbnode *np = VTOSMB(vp); 25344bff34e3Sthurlow int error = 0; 25354bff34e3Sthurlow smbmntinfo_t *smi; 25364bff34e3Sthurlow 25374bff34e3Sthurlow smi = VTOSMI(vp); 25384bff34e3Sthurlow 2539*a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 25404bff34e3Sthurlow return (EIO); 25414bff34e3Sthurlow 25424bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 25434bff34e3Sthurlow return (EIO); 25444bff34e3Sthurlow 25454bff34e3Sthurlow /* 25464bff34e3Sthurlow * Require read access in the directory. 25474bff34e3Sthurlow */ 25484bff34e3Sthurlow error = smbfs_access(vp, VREAD, 0, cr, ct); 25494bff34e3Sthurlow if (error) 25504bff34e3Sthurlow return (error); 25514bff34e3Sthurlow 25524bff34e3Sthurlow ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER)); 25534bff34e3Sthurlow 25544bff34e3Sthurlow /* 25554bff34e3Sthurlow * XXX: Todo readdir cache here 25564bff34e3Sthurlow * Note: NFS code is just below this. 25574bff34e3Sthurlow * 25584bff34e3Sthurlow * I am serializing the entire readdir opreation 25594bff34e3Sthurlow * now since we have not yet implemented readdir 25604bff34e3Sthurlow * cache. This fix needs to be revisited once 25614bff34e3Sthurlow * we implement readdir cache. 25624bff34e3Sthurlow */ 25634bff34e3Sthurlow if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp))) 25644bff34e3Sthurlow return (EINTR); 25654bff34e3Sthurlow 25664bff34e3Sthurlow error = smbfs_readvdir(vp, uiop, cr, eofp, ct); 25674bff34e3Sthurlow 25684bff34e3Sthurlow smbfs_rw_exit(&np->r_lkserlock); 25694bff34e3Sthurlow 25704bff34e3Sthurlow return (error); 25714bff34e3Sthurlow } 25724bff34e3Sthurlow 25734bff34e3Sthurlow /* ARGSUSED */ 25744bff34e3Sthurlow static int 25754bff34e3Sthurlow smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp, 25764bff34e3Sthurlow caller_context_t *ct) 25774bff34e3Sthurlow { 25785ecede33SGordon Ross /* 25795ecede33SGordon Ross * Note: "limit" tells the SMB-level FindFirst/FindNext 25805ecede33SGordon Ross * functions how many directory entries to request in 25815ecede33SGordon Ross * each OtW call. It needs to be large enough so that 25825ecede33SGordon Ross * we don't make lots of tiny OtW requests, but there's 25835ecede33SGordon Ross * no point making it larger than the maximum number of 25845ecede33SGordon Ross * OtW entries that would fit in a maximum sized trans2 25855ecede33SGordon Ross * response (64k / 48). Beyond that, it's just tuning. 25865ecede33SGordon Ross * WinNT used 512, Win2k used 1366. We use 1000. 25875ecede33SGordon Ross */ 25885ecede33SGordon Ross static const int limit = 1000; 25895ecede33SGordon Ross /* Largest possible dirent size. */ 25905ecede33SGordon Ross static const size_t dbufsiz = DIRENT64_RECLEN(SMB_MAXFNAMELEN); 25914bff34e3Sthurlow struct smb_cred scred; 25924bff34e3Sthurlow vnode_t *newvp; 25934bff34e3Sthurlow struct smbnode *np = VTOSMB(vp); 25944bff34e3Sthurlow struct smbfs_fctx *ctx; 25955ecede33SGordon Ross struct dirent64 *dp; 25965ecede33SGordon Ross ssize_t save_resid; 25975ecede33SGordon Ross offset_t save_offset; /* 64 bits */ 25985ecede33SGordon Ross int offset; /* yes, 32 bits */ 25995ecede33SGordon Ross int nmlen, error; 26005ecede33SGordon Ross ushort_t reclen; 26014bff34e3Sthurlow 2602*a19609f8Sjv ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone_ref.zref_zone); 26034bff34e3Sthurlow 26044bff34e3Sthurlow /* Make sure we serialize for n_dirseq use. */ 26054bff34e3Sthurlow ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_WRITER)); 26064bff34e3Sthurlow 26075ecede33SGordon Ross /* 26085ecede33SGordon Ross * Make sure smbfs_open filled in n_dirseq 26095ecede33SGordon Ross */ 26105ecede33SGordon Ross if (np->n_dirseq == NULL) 26115ecede33SGordon Ross return (EBADF); 26125ecede33SGordon Ross 26135ecede33SGordon Ross /* Check for overflow of (32-bit) directory offset. */ 26145ecede33SGordon Ross if (uio->uio_loffset < 0 || uio->uio_loffset > INT32_MAX || 26155ecede33SGordon Ross (uio->uio_loffset + uio->uio_resid) > INT32_MAX) 26165ecede33SGordon Ross return (EINVAL); 26175ecede33SGordon Ross 26185ecede33SGordon Ross /* Require space for at least one dirent. */ 26195ecede33SGordon Ross if (uio->uio_resid < dbufsiz) 26204bff34e3Sthurlow return (EINVAL); 26214bff34e3Sthurlow 26224bff34e3Sthurlow SMBVDEBUG("dirname='%s'\n", np->n_rpath); 2623613a2f6bSGordon Ross smb_credinit(&scred, cr); 26244bff34e3Sthurlow dp = kmem_alloc(dbufsiz, KM_SLEEP); 26254bff34e3Sthurlow 26265ecede33SGordon Ross save_resid = uio->uio_resid; 26275ecede33SGordon Ross save_offset = uio->uio_loffset; 26285ecede33SGordon Ross offset = uio->uio_offset; 26295ecede33SGordon Ross SMBVDEBUG("in: offset=%d, resid=%d\n", 26305ecede33SGordon Ross (int)uio->uio_offset, (int)uio->uio_resid); 26315ecede33SGordon Ross error = 0; 26324bff34e3Sthurlow 26334bff34e3Sthurlow /* 26344bff34e3Sthurlow * Generate the "." and ".." entries here so we can 26354bff34e3Sthurlow * (1) make sure they appear (but only once), and 26364bff34e3Sthurlow * (2) deal with getting their I numbers which the 26374bff34e3Sthurlow * findnext below does only for normal names. 26384bff34e3Sthurlow */ 26395ecede33SGordon Ross while (offset < FIRST_DIROFS) { 26405ecede33SGordon Ross /* 26415ecede33SGordon Ross * Tricky bit filling in the first two: 26425ecede33SGordon Ross * offset 0 is ".", offset 1 is ".." 26435ecede33SGordon Ross * so strlen of these is offset+1. 26445ecede33SGordon Ross */ 26454bff34e3Sthurlow reclen = DIRENT64_RECLEN(offset + 1); 26465ecede33SGordon Ross if (uio->uio_resid < reclen) 26475ecede33SGordon Ross goto out; 26484bff34e3Sthurlow bzero(dp, reclen); 26494bff34e3Sthurlow dp->d_reclen = reclen; 26504bff34e3Sthurlow dp->d_name[0] = '.'; 26514bff34e3Sthurlow dp->d_name[1] = '.'; 26524bff34e3Sthurlow dp->d_name[offset + 1] = '\0'; 26534bff34e3Sthurlow /* 26544bff34e3Sthurlow * Want the real I-numbers for the "." and ".." 26554bff34e3Sthurlow * entries. For these two names, we know that 26565ecede33SGordon Ross * smbfslookup can get the nodes efficiently. 26574bff34e3Sthurlow */ 26584bff34e3Sthurlow error = smbfslookup(vp, dp->d_name, &newvp, cr, 1, ct); 26594bff34e3Sthurlow if (error) { 26604bff34e3Sthurlow dp->d_ino = np->n_ino + offset; /* fiction */ 26614bff34e3Sthurlow } else { 26624bff34e3Sthurlow dp->d_ino = VTOSMB(newvp)->n_ino; 26634bff34e3Sthurlow VN_RELE(newvp); 26644bff34e3Sthurlow } 26655ecede33SGordon Ross /* 26665ecede33SGordon Ross * Note: d_off is the offset that a user-level program 26675ecede33SGordon Ross * should seek to for reading the NEXT directory entry. 26685ecede33SGordon Ross * See libc: readdir, telldir, seekdir 26695ecede33SGordon Ross */ 26705ecede33SGordon Ross dp->d_off = offset + 1; 26715ecede33SGordon Ross error = uiomove(dp, reclen, UIO_READ, uio); 26724bff34e3Sthurlow if (error) 26734bff34e3Sthurlow goto out; 26745ecede33SGordon Ross /* 26755ecede33SGordon Ross * Note: uiomove updates uio->uio_offset, 26765ecede33SGordon Ross * but we want it to be our "cookie" value, 26775ecede33SGordon Ross * which just counts dirents ignoring size. 26785ecede33SGordon Ross */ 26794bff34e3Sthurlow uio->uio_offset = ++offset; 26804bff34e3Sthurlow } 26815ecede33SGordon Ross 26825ecede33SGordon Ross /* 26835ecede33SGordon Ross * If there was a backward seek, we have to reopen. 26845ecede33SGordon Ross */ 26855ecede33SGordon Ross if (offset < np->n_dirofs) { 26865ecede33SGordon Ross SMBVDEBUG("Reopening search %d:%d\n", 26875ecede33SGordon Ross offset, np->n_dirofs); 26884bff34e3Sthurlow error = smbfs_smb_findopen(np, "*", 1, 26894bff34e3Sthurlow SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, 26904bff34e3Sthurlow &scred, &ctx); 26914bff34e3Sthurlow if (error) { 26924bff34e3Sthurlow SMBVDEBUG("can not open search, error = %d", error); 26934bff34e3Sthurlow goto out; 26944bff34e3Sthurlow } 26955ecede33SGordon Ross /* free the old one */ 26965ecede33SGordon Ross (void) smbfs_smb_findclose(np->n_dirseq, &scred); 26975ecede33SGordon Ross /* save the new one */ 26984bff34e3Sthurlow np->n_dirseq = ctx; 26995ecede33SGordon Ross np->n_dirofs = FIRST_DIROFS; 27005ecede33SGordon Ross } else { 27014bff34e3Sthurlow ctx = np->n_dirseq; 27025ecede33SGordon Ross } 27035ecede33SGordon Ross 27045ecede33SGordon Ross /* 27055ecede33SGordon Ross * Skip entries before the requested offset. 27065ecede33SGordon Ross */ 27074bff34e3Sthurlow while (np->n_dirofs < offset) { 27085ecede33SGordon Ross error = smbfs_smb_findnext(ctx, limit, &scred); 27095ecede33SGordon Ross if (error != 0) 27104bff34e3Sthurlow goto out; 27115ecede33SGordon Ross np->n_dirofs++; 27124bff34e3Sthurlow } 27135ecede33SGordon Ross 27145ecede33SGordon Ross /* 27155ecede33SGordon Ross * While there's room in the caller's buffer: 27165ecede33SGordon Ross * get a directory entry from SMB, 27175ecede33SGordon Ross * convert to a dirent, copyout. 27185ecede33SGordon Ross * We stop when there is no longer room for a 27195ecede33SGordon Ross * maximum sized dirent because we must decide 27205ecede33SGordon Ross * before we know anything about the next entry. 27215ecede33SGordon Ross */ 27225ecede33SGordon Ross while (uio->uio_resid >= dbufsiz) { 27234bff34e3Sthurlow error = smbfs_smb_findnext(ctx, limit, &scred); 27245ecede33SGordon Ross if (error != 0) 27255ecede33SGordon Ross goto out; 27264bff34e3Sthurlow np->n_dirofs++; 27275ecede33SGordon Ross 27284bff34e3Sthurlow /* Sanity check the name length. */ 27294bff34e3Sthurlow nmlen = ctx->f_nmlen; 2730613a2f6bSGordon Ross if (nmlen > SMB_MAXFNAMELEN) { 2731613a2f6bSGordon Ross nmlen = SMB_MAXFNAMELEN; 27324bff34e3Sthurlow SMBVDEBUG("Truncating name: %s\n", ctx->f_name); 27334bff34e3Sthurlow } 27344bff34e3Sthurlow if (smbfs_fastlookup) { 273502d09e03SGordon Ross /* See comment at smbfs_fastlookup above. */ 27365ecede33SGordon Ross if (smbfs_nget(vp, ctx->f_name, nmlen, 27375ecede33SGordon Ross &ctx->f_attr, &newvp) == 0) 27384bff34e3Sthurlow VN_RELE(newvp); 27394bff34e3Sthurlow } 27405ecede33SGordon Ross 27415ecede33SGordon Ross reclen = DIRENT64_RECLEN(nmlen); 27425ecede33SGordon Ross bzero(dp, reclen); 27435ecede33SGordon Ross dp->d_reclen = reclen; 27445ecede33SGordon Ross bcopy(ctx->f_name, dp->d_name, nmlen); 27455ecede33SGordon Ross dp->d_name[nmlen] = '\0'; 274602d09e03SGordon Ross dp->d_ino = ctx->f_inum; 27475ecede33SGordon Ross dp->d_off = offset + 1; /* See d_off comment above */ 27485ecede33SGordon Ross error = uiomove(dp, reclen, UIO_READ, uio); 27494bff34e3Sthurlow if (error) 27505ecede33SGordon Ross goto out; 27515ecede33SGordon Ross /* See comment re. uio_offset above. */ 27524bff34e3Sthurlow uio->uio_offset = ++offset; 27534bff34e3Sthurlow } 27545ecede33SGordon Ross 27554bff34e3Sthurlow out: 27565ecede33SGordon Ross /* 27575ecede33SGordon Ross * When we come to the end of a directory, the 27585ecede33SGordon Ross * SMB-level functions return ENOENT, but the 27595ecede33SGordon Ross * caller is not expecting an error return. 27605ecede33SGordon Ross * 27615ecede33SGordon Ross * Also note that we must delay the call to 27625ecede33SGordon Ross * smbfs_smb_findclose(np->n_dirseq, ...) 27635ecede33SGordon Ross * until smbfs_close so that all reads at the 27645ecede33SGordon Ross * end of the directory will return no data. 27655ecede33SGordon Ross */ 27665ecede33SGordon Ross if (error == ENOENT) { 27675ecede33SGordon Ross error = 0; 27685ecede33SGordon Ross if (eofp) 27695ecede33SGordon Ross *eofp = 1; 27705ecede33SGordon Ross } 27715ecede33SGordon Ross /* 27725ecede33SGordon Ross * If we encountered an error (i.e. "access denied") 27735ecede33SGordon Ross * from the FindFirst call, we will have copied out 27745ecede33SGordon Ross * the "." and ".." entries leaving offset == 2. 27755ecede33SGordon Ross * In that case, restore the original offset/resid 27765ecede33SGordon Ross * so the caller gets no data with the error. 27775ecede33SGordon Ross */ 27785ecede33SGordon Ross if (error != 0 && offset == FIRST_DIROFS) { 27795ecede33SGordon Ross uio->uio_loffset = save_offset; 27805ecede33SGordon Ross uio->uio_resid = save_resid; 27815ecede33SGordon Ross } 27825ecede33SGordon Ross SMBVDEBUG("out: offset=%d, resid=%d\n", 27835ecede33SGordon Ross (int)uio->uio_offset, (int)uio->uio_resid); 27845ecede33SGordon Ross 27854bff34e3Sthurlow kmem_free(dp, dbufsiz); 27864bff34e3Sthurlow smb_credrele(&scred); 27874bff34e3Sthurlow return (error); 27884bff34e3Sthurlow } 27894bff34e3Sthurlow 27904bff34e3Sthurlow 27914bff34e3Sthurlow /* 27924bff34e3Sthurlow * The pair of functions VOP_RWLOCK, VOP_RWUNLOCK 27934bff34e3Sthurlow * are optional functions that are called by: 27944bff34e3Sthurlow * getdents, before/after VOP_READDIR 27954bff34e3Sthurlow * pread, before/after ... VOP_READ 27964bff34e3Sthurlow * pwrite, before/after ... VOP_WRITE 27974bff34e3Sthurlow * (other places) 27984bff34e3Sthurlow * 27994bff34e3Sthurlow * Careful here: None of the above check for any 28004bff34e3Sthurlow * error returns from VOP_RWLOCK / VOP_RWUNLOCK! 28014bff34e3Sthurlow * In fact, the return value from _rwlock is NOT 28024bff34e3Sthurlow * an error code, but V_WRITELOCK_TRUE / _FALSE. 28034bff34e3Sthurlow * 28044bff34e3Sthurlow * Therefore, it's up to _this_ code to make sure 28054bff34e3Sthurlow * the lock state remains balanced, which means 28064bff34e3Sthurlow * we can't "bail out" on interrupts, etc. 28074bff34e3Sthurlow */ 28084bff34e3Sthurlow 28094bff34e3Sthurlow /* ARGSUSED2 */ 28104bff34e3Sthurlow static int 28114bff34e3Sthurlow smbfs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp) 28124bff34e3Sthurlow { 28134bff34e3Sthurlow smbnode_t *np = VTOSMB(vp); 28144bff34e3Sthurlow 28154bff34e3Sthurlow if (!write_lock) { 28164bff34e3Sthurlow (void) smbfs_rw_enter_sig(&np->r_rwlock, RW_READER, FALSE); 28174bff34e3Sthurlow return (V_WRITELOCK_FALSE); 28184bff34e3Sthurlow } 28194bff34e3Sthurlow 28204bff34e3Sthurlow 28214bff34e3Sthurlow (void) smbfs_rw_enter_sig(&np->r_rwlock, RW_WRITER, FALSE); 28224bff34e3Sthurlow return (V_WRITELOCK_TRUE); 28234bff34e3Sthurlow } 28244bff34e3Sthurlow 28254bff34e3Sthurlow /* ARGSUSED */ 28264bff34e3Sthurlow static void 28274bff34e3Sthurlow smbfs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp) 28284bff34e3Sthurlow { 28294bff34e3Sthurlow smbnode_t *np = VTOSMB(vp); 28304bff34e3Sthurlow 28314bff34e3Sthurlow smbfs_rw_exit(&np->r_rwlock); 28324bff34e3Sthurlow } 28334bff34e3Sthurlow 28344bff34e3Sthurlow 28354bff34e3Sthurlow /* ARGSUSED */ 28364bff34e3Sthurlow static int 28374bff34e3Sthurlow smbfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct) 28384bff34e3Sthurlow { 28394bff34e3Sthurlow smbmntinfo_t *smi; 28404bff34e3Sthurlow 28414bff34e3Sthurlow smi = VTOSMI(vp); 28424bff34e3Sthurlow 2843*a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 28444bff34e3Sthurlow return (EPERM); 28454bff34e3Sthurlow 28464bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 28474bff34e3Sthurlow return (EIO); 28484bff34e3Sthurlow 28494bff34e3Sthurlow /* 28504bff34e3Sthurlow * Because we stuff the readdir cookie into the offset field 28514bff34e3Sthurlow * someone may attempt to do an lseek with the cookie which 28524bff34e3Sthurlow * we want to succeed. 28534bff34e3Sthurlow */ 28544bff34e3Sthurlow if (vp->v_type == VDIR) 28554bff34e3Sthurlow return (0); 28564bff34e3Sthurlow 28574bff34e3Sthurlow /* Like NFS3, just check for 63-bit overflow. */ 28584bff34e3Sthurlow if (*noffp < 0) 28594bff34e3Sthurlow return (EINVAL); 28604bff34e3Sthurlow 28614bff34e3Sthurlow return (0); 28624bff34e3Sthurlow } 28634bff34e3Sthurlow 28644bff34e3Sthurlow 28654bff34e3Sthurlow /* 28664bff34e3Sthurlow * XXX 28674bff34e3Sthurlow * This op may need to support PSARC 2007/440, nbmand changes for CIFS Service. 28684bff34e3Sthurlow */ 28694bff34e3Sthurlow static int 28704bff34e3Sthurlow smbfs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag, 28714bff34e3Sthurlow offset_t offset, struct flk_callback *flk_cbp, cred_t *cr, 28724bff34e3Sthurlow caller_context_t *ct) 28734bff34e3Sthurlow { 2874*a19609f8Sjv if (curproc->p_zone != VTOSMI(vp)->smi_zone_ref.zref_zone) 28754bff34e3Sthurlow return (EIO); 28764bff34e3Sthurlow 28774bff34e3Sthurlow if (VTOSMI(vp)->smi_flags & SMI_LLOCK) 28784bff34e3Sthurlow return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct)); 28794bff34e3Sthurlow else 28804bff34e3Sthurlow return (ENOSYS); 28814bff34e3Sthurlow } 28824bff34e3Sthurlow 28834bff34e3Sthurlow /* 28844bff34e3Sthurlow * Free storage space associated with the specified vnode. The portion 28854bff34e3Sthurlow * to be freed is specified by bfp->l_start and bfp->l_len (already 28864bff34e3Sthurlow * normalized to a "whence" of 0). 28874bff34e3Sthurlow * 28884bff34e3Sthurlow * Called by fcntl(fd, F_FREESP, lkp) for libc:ftruncate, etc. 28894bff34e3Sthurlow */ 28904bff34e3Sthurlow /* ARGSUSED */ 28914bff34e3Sthurlow static int 28924bff34e3Sthurlow smbfs_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag, 28934bff34e3Sthurlow offset_t offset, cred_t *cr, caller_context_t *ct) 28944bff34e3Sthurlow { 28954bff34e3Sthurlow int error; 28964bff34e3Sthurlow smbmntinfo_t *smi; 28974bff34e3Sthurlow 28984bff34e3Sthurlow smi = VTOSMI(vp); 28994bff34e3Sthurlow 2900*a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 29014bff34e3Sthurlow return (EIO); 29024bff34e3Sthurlow 29034bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 29044bff34e3Sthurlow return (EIO); 29054bff34e3Sthurlow 290691d632c8Sgwr /* Caller (fcntl) has checked v_type */ 29074bff34e3Sthurlow ASSERT(vp->v_type == VREG); 29084bff34e3Sthurlow if (cmd != F_FREESP) 29094bff34e3Sthurlow return (EINVAL); 29104bff34e3Sthurlow 29114bff34e3Sthurlow /* 29124bff34e3Sthurlow * Like NFS3, no 32-bit offset checks here. 29134bff34e3Sthurlow * Our SMB layer takes care to return EFBIG 29144bff34e3Sthurlow * when it has to fallback to a 32-bit call. 29154bff34e3Sthurlow */ 29164bff34e3Sthurlow 29174bff34e3Sthurlow error = convoff(vp, bfp, 0, offset); 29184bff34e3Sthurlow if (!error) { 29194bff34e3Sthurlow ASSERT(bfp->l_start >= 0); 29204bff34e3Sthurlow if (bfp->l_len == 0) { 29214bff34e3Sthurlow struct vattr va; 29224bff34e3Sthurlow 29234bff34e3Sthurlow /* 29244bff34e3Sthurlow * ftruncate should not change the ctime and 29254bff34e3Sthurlow * mtime if we truncate the file to its 29264bff34e3Sthurlow * previous size. 29274bff34e3Sthurlow */ 29284bff34e3Sthurlow va.va_mask = AT_SIZE; 29294bff34e3Sthurlow error = smbfsgetattr(vp, &va, cr); 29304bff34e3Sthurlow if (error || va.va_size == bfp->l_start) 29314bff34e3Sthurlow return (error); 29324bff34e3Sthurlow va.va_mask = AT_SIZE; 29334bff34e3Sthurlow va.va_size = bfp->l_start; 29344bff34e3Sthurlow error = smbfssetattr(vp, &va, 0, cr); 29354bff34e3Sthurlow } else 29364bff34e3Sthurlow error = EINVAL; 29374bff34e3Sthurlow } 29384bff34e3Sthurlow 29394bff34e3Sthurlow return (error); 29404bff34e3Sthurlow } 29414bff34e3Sthurlow 29424bff34e3Sthurlow /* ARGSUSED */ 29434bff34e3Sthurlow static int 29444bff34e3Sthurlow smbfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr, 29454bff34e3Sthurlow caller_context_t *ct) 29464bff34e3Sthurlow { 294791d632c8Sgwr vfs_t *vfs; 29484bff34e3Sthurlow smbmntinfo_t *smi; 29494bff34e3Sthurlow struct smb_share *ssp; 29504bff34e3Sthurlow 295191d632c8Sgwr vfs = vp->v_vfsp; 295291d632c8Sgwr smi = VFTOSMI(vfs); 29534bff34e3Sthurlow 2954*a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 29554bff34e3Sthurlow return (EIO); 29564bff34e3Sthurlow 29574bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 29584bff34e3Sthurlow return (EIO); 29594bff34e3Sthurlow 29604bff34e3Sthurlow switch (cmd) { 29614bff34e3Sthurlow case _PC_FILESIZEBITS: 29624bff34e3Sthurlow ssp = smi->smi_share; 29634bff34e3Sthurlow if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES) 29644bff34e3Sthurlow *valp = 64; 29654bff34e3Sthurlow else 29664bff34e3Sthurlow *valp = 32; 29674bff34e3Sthurlow break; 29684bff34e3Sthurlow 29694bff34e3Sthurlow case _PC_LINK_MAX: 29704bff34e3Sthurlow /* We only ever report one link to an object */ 29714bff34e3Sthurlow *valp = 1; 29724bff34e3Sthurlow break; 29734bff34e3Sthurlow 29747568150aSgwr case _PC_ACL_ENABLED: 29757568150aSgwr /* 297602d09e03SGordon Ross * Always indicate that ACLs are enabled and 297702d09e03SGordon Ross * that we support ACE_T format, otherwise 297802d09e03SGordon Ross * libsec will ask for ACLENT_T format data 297902d09e03SGordon Ross * which we don't support. 29807568150aSgwr */ 29817568150aSgwr *valp = _ACL_ACE_ENABLED; 29827568150aSgwr break; 29837568150aSgwr 29844bff34e3Sthurlow case _PC_SYMLINK_MAX: /* No symlinks until we do Unix extensions */ 29854bff34e3Sthurlow *valp = 0; 29864bff34e3Sthurlow break; 29874bff34e3Sthurlow 298891d632c8Sgwr case _PC_XATTR_EXISTS: 298991d632c8Sgwr if (vfs->vfs_flag & VFS_XATTR) { 299091d632c8Sgwr *valp = smbfs_xa_exists(vp, cr); 299191d632c8Sgwr break; 299291d632c8Sgwr } 299391d632c8Sgwr return (EINVAL); 299491d632c8Sgwr 29953b862e9aSRoger A. Faulkner case _PC_TIMESTAMP_RESOLUTION: 299602d09e03SGordon Ross /* 299702d09e03SGordon Ross * Windows times are tenths of microseconds 299802d09e03SGordon Ross * (multiples of 100 nanoseconds). 299902d09e03SGordon Ross */ 300002d09e03SGordon Ross *valp = 100L; 30013b862e9aSRoger A. Faulkner break; 30023b862e9aSRoger A. Faulkner 30034bff34e3Sthurlow default: 30044bff34e3Sthurlow return (fs_pathconf(vp, cmd, valp, cr, ct)); 30054bff34e3Sthurlow } 30064bff34e3Sthurlow return (0); 30074bff34e3Sthurlow } 30084bff34e3Sthurlow 30097568150aSgwr /* ARGSUSED */ 30107568150aSgwr static int 30117568150aSgwr smbfs_getsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr, 30127568150aSgwr caller_context_t *ct) 30137568150aSgwr { 30147568150aSgwr vfs_t *vfsp; 30157568150aSgwr smbmntinfo_t *smi; 301602d09e03SGordon Ross int error; 30177568150aSgwr uint_t mask; 30187568150aSgwr 30197568150aSgwr vfsp = vp->v_vfsp; 30207568150aSgwr smi = VFTOSMI(vfsp); 30217568150aSgwr 3022*a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 30237568150aSgwr return (EIO); 30247568150aSgwr 30257568150aSgwr if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 30267568150aSgwr return (EIO); 30277568150aSgwr 30287568150aSgwr /* 30297568150aSgwr * Our _pathconf indicates _ACL_ACE_ENABLED, 30307568150aSgwr * so we should only see VSA_ACE, etc here. 30317568150aSgwr * Note: vn_create asks for VSA_DFACLCNT, 30327568150aSgwr * and it expects ENOSYS and empty data. 30337568150aSgwr */ 30347568150aSgwr mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT | 30357568150aSgwr VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES); 30367568150aSgwr if (mask == 0) 30377568150aSgwr return (ENOSYS); 30387568150aSgwr 303902d09e03SGordon Ross if (smi->smi_flags & SMI_ACL) 3040bd7c6f51SGordon Ross error = smbfs_acl_getvsa(vp, vsa, flag, cr); 304102d09e03SGordon Ross else 30427568150aSgwr error = ENOSYS; 30437568150aSgwr 30447568150aSgwr if (error == ENOSYS) 30457568150aSgwr error = fs_fab_acl(vp, vsa, flag, cr, ct); 30467568150aSgwr 30477568150aSgwr return (error); 30487568150aSgwr } 30497568150aSgwr 30507568150aSgwr /* ARGSUSED */ 30517568150aSgwr static int 30527568150aSgwr smbfs_setsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr, 30537568150aSgwr caller_context_t *ct) 30547568150aSgwr { 30557568150aSgwr vfs_t *vfsp; 30567568150aSgwr smbmntinfo_t *smi; 30577568150aSgwr int error; 30587568150aSgwr uint_t mask; 30597568150aSgwr 30607568150aSgwr vfsp = vp->v_vfsp; 30617568150aSgwr smi = VFTOSMI(vfsp); 30627568150aSgwr 3063*a19609f8Sjv if (curproc->p_zone != smi->smi_zone_ref.zref_zone) 30647568150aSgwr return (EIO); 30657568150aSgwr 30667568150aSgwr if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 30677568150aSgwr return (EIO); 30687568150aSgwr 30697568150aSgwr /* 30707568150aSgwr * Our _pathconf indicates _ACL_ACE_ENABLED, 30717568150aSgwr * so we should only see VSA_ACE, etc here. 30727568150aSgwr */ 30737568150aSgwr mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT); 30747568150aSgwr if (mask == 0) 30757568150aSgwr return (ENOSYS); 30767568150aSgwr 30777568150aSgwr if (vfsp->vfs_flag & VFS_RDONLY) 30787568150aSgwr return (EROFS); 30797568150aSgwr 308002d09e03SGordon Ross /* 308102d09e03SGordon Ross * Allow only the mount owner to do this. 308202d09e03SGordon Ross * See comments at smbfs_access_rwx. 308302d09e03SGordon Ross */ 308402d09e03SGordon Ross error = secpolicy_vnode_setdac(cr, smi->smi_uid); 308502d09e03SGordon Ross if (error != 0) 308602d09e03SGordon Ross return (error); 308702d09e03SGordon Ross 308802d09e03SGordon Ross if (smi->smi_flags & SMI_ACL) 3089bd7c6f51SGordon Ross error = smbfs_acl_setvsa(vp, vsa, flag, cr); 309002d09e03SGordon Ross else 30917568150aSgwr error = ENOSYS; 30927568150aSgwr 30937568150aSgwr return (error); 30947568150aSgwr } 30954bff34e3Sthurlow 30964bff34e3Sthurlow 30974bff34e3Sthurlow /* 30984bff34e3Sthurlow * XXX 30994bff34e3Sthurlow * This op should eventually support PSARC 2007/268. 31004bff34e3Sthurlow */ 31014bff34e3Sthurlow static int 31024bff34e3Sthurlow smbfs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr, 31034bff34e3Sthurlow caller_context_t *ct) 31044bff34e3Sthurlow { 3105*a19609f8Sjv if (curproc->p_zone != VTOSMI(vp)->smi_zone_ref.zref_zone) 31064bff34e3Sthurlow return (EIO); 31074bff34e3Sthurlow 31084bff34e3Sthurlow if (VTOSMI(vp)->smi_flags & SMI_LLOCK) 31094bff34e3Sthurlow return (fs_shrlock(vp, cmd, shr, flag, cr, ct)); 31104bff34e3Sthurlow else 31114bff34e3Sthurlow return (ENOSYS); 31124bff34e3Sthurlow } 3113