14bff34e3Sthurlow /* 24bff34e3Sthurlow * Copyright (c) 2000-2001 Boris Popov 34bff34e3Sthurlow * All rights reserved. 44bff34e3Sthurlow * 54bff34e3Sthurlow * Redistribution and use in source and binary forms, with or without 64bff34e3Sthurlow * modification, are permitted provided that the following conditions 74bff34e3Sthurlow * are met: 84bff34e3Sthurlow * 1. Redistributions of source code must retain the above copyright 94bff34e3Sthurlow * notice, this list of conditions and the following disclaimer. 104bff34e3Sthurlow * 2. Redistributions in binary form must reproduce the above copyright 114bff34e3Sthurlow * notice, this list of conditions and the following disclaimer in the 124bff34e3Sthurlow * documentation and/or other materials provided with the distribution. 134bff34e3Sthurlow * 3. All advertising materials mentioning features or use of this software 144bff34e3Sthurlow * must display the following acknowledgement: 154bff34e3Sthurlow * This product includes software developed by Boris Popov. 164bff34e3Sthurlow * 4. Neither the name of the author nor the names of any co-contributors 174bff34e3Sthurlow * may be used to endorse or promote products derived from this software 184bff34e3Sthurlow * without specific prior written permission. 194bff34e3Sthurlow * 204bff34e3Sthurlow * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 214bff34e3Sthurlow * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 224bff34e3Sthurlow * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 234bff34e3Sthurlow * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 244bff34e3Sthurlow * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 254bff34e3Sthurlow * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 264bff34e3Sthurlow * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 274bff34e3Sthurlow * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 284bff34e3Sthurlow * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 294bff34e3Sthurlow * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 304bff34e3Sthurlow * SUCH DAMAGE. 314bff34e3Sthurlow * 324bff34e3Sthurlow * $Id: smbfs_vnops.c,v 1.128.36.1 2005/05/27 02:35:28 lindak Exp $ 334bff34e3Sthurlow */ 344bff34e3Sthurlow 354bff34e3Sthurlow /* 362f5e3e91SGordon Ross * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 374bff34e3Sthurlow * Use is subject to license terms. 384bff34e3Sthurlow */ 394bff34e3Sthurlow 404bff34e3Sthurlow #include <sys/systm.h> 414bff34e3Sthurlow #include <sys/cred.h> 424bff34e3Sthurlow #include <sys/vnode.h> 434bff34e3Sthurlow #include <sys/vfs.h> 447568150aSgwr #include <sys/filio.h> 454bff34e3Sthurlow #include <sys/uio.h> 464bff34e3Sthurlow #include <sys/dirent.h> 474bff34e3Sthurlow #include <sys/errno.h> 48613a2f6bSGordon Ross #include <sys/sunddi.h> 494bff34e3Sthurlow #include <sys/sysmacros.h> 504bff34e3Sthurlow #include <sys/kmem.h> 514bff34e3Sthurlow #include <sys/cmn_err.h> 524bff34e3Sthurlow #include <sys/dnlc.h> 534bff34e3Sthurlow #include <sys/vfs_opreg.h> 544bff34e3Sthurlow #include <sys/policy.h> 554bff34e3Sthurlow 564bff34e3Sthurlow #include <netsmb/smb_osdep.h> 574bff34e3Sthurlow #include <netsmb/smb.h> 584bff34e3Sthurlow #include <netsmb/smb_conn.h> 594bff34e3Sthurlow #include <netsmb/smb_subr.h> 604bff34e3Sthurlow 614bff34e3Sthurlow #include <smbfs/smbfs.h> 624bff34e3Sthurlow #include <smbfs/smbfs_node.h> 634bff34e3Sthurlow #include <smbfs/smbfs_subr.h> 644bff34e3Sthurlow 657568150aSgwr #include <sys/fs/smbfs_ioctl.h> 664bff34e3Sthurlow #include <fs/fs_subr.h> 674bff34e3Sthurlow 68*5ecede33SGordon Ross /* 69*5ecede33SGordon Ross * We assign directory offsets like the NFS client, where the 70*5ecede33SGordon Ross * offset increments by _one_ after each directory entry. 71*5ecede33SGordon Ross * Further, the entries "." and ".." are always at offsets 72*5ecede33SGordon Ross * zero and one (respectively) and the "real" entries from 73*5ecede33SGordon Ross * the server appear at offsets starting with two. This 74*5ecede33SGordon Ross * macro is used to initialize the n_dirofs field after 75*5ecede33SGordon Ross * setting n_dirseq with a _findopen call. 76*5ecede33SGordon Ross */ 77*5ecede33SGordon Ross #define FIRST_DIROFS 2 78*5ecede33SGordon Ross 794bff34e3Sthurlow /* 804bff34e3Sthurlow * These characters are illegal in NTFS file names. 814bff34e3Sthurlow * ref: http://support.microsoft.com/kb/147438 8291d632c8Sgwr * 8391d632c8Sgwr * Careful! The check in the XATTR case skips the 8491d632c8Sgwr * first character to allow colon in XATTR names. 854bff34e3Sthurlow */ 864bff34e3Sthurlow static const char illegal_chars[] = { 8791d632c8Sgwr ':', /* colon - keep this first! */ 884bff34e3Sthurlow '\\', /* back slash */ 894bff34e3Sthurlow '/', /* slash */ 904bff34e3Sthurlow '*', /* asterisk */ 914bff34e3Sthurlow '?', /* question mark */ 924bff34e3Sthurlow '"', /* double quote */ 934bff34e3Sthurlow '<', /* less than sign */ 944bff34e3Sthurlow '>', /* greater than sign */ 954bff34e3Sthurlow '|', /* vertical bar */ 964bff34e3Sthurlow 0 974bff34e3Sthurlow }; 984bff34e3Sthurlow 994bff34e3Sthurlow /* 1004bff34e3Sthurlow * Turning this on causes nodes to be created in the cache 1014bff34e3Sthurlow * during directory listings. The "fast" claim is debatable, 1024bff34e3Sthurlow * and the effects on the cache can be undesirable. 1034bff34e3Sthurlow */ 1044bff34e3Sthurlow 1054bff34e3Sthurlow /* local static function defines */ 1064bff34e3Sthurlow 10791d632c8Sgwr #ifdef USE_DNLC 10891d632c8Sgwr static int smbfslookup_dnlc(vnode_t *dvp, char *nm, vnode_t **vpp, 10991d632c8Sgwr cred_t *cr); 11091d632c8Sgwr #endif 1114bff34e3Sthurlow static int smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, 1124bff34e3Sthurlow int dnlc, caller_context_t *); 1134bff34e3Sthurlow static int smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, 1144bff34e3Sthurlow cred_t *cr, caller_context_t *); 1154bff34e3Sthurlow static int smbfssetattr(vnode_t *, struct vattr *, int, cred_t *); 1164bff34e3Sthurlow static int smbfs_accessx(void *, int, cred_t *); 1174bff34e3Sthurlow static int smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp, 1184bff34e3Sthurlow caller_context_t *); 1194bff34e3Sthurlow /* 1204bff34e3Sthurlow * These are the vnode ops routines which implement the vnode interface to 1214bff34e3Sthurlow * the networked file system. These routines just take their parameters, 1224bff34e3Sthurlow * make them look networkish by putting the right info into interface structs, 1234bff34e3Sthurlow * and then calling the appropriate remote routine(s) to do the work. 1244bff34e3Sthurlow * 1254bff34e3Sthurlow * Note on directory name lookup cacheing: If we detect a stale fhandle, 1264bff34e3Sthurlow * we purge the directory cache relative to that vnode. This way, the 1274bff34e3Sthurlow * user won't get burned by the cache repeatedly. See <smbfs/smbnode.h> for 1284bff34e3Sthurlow * more details on smbnode locking. 1294bff34e3Sthurlow */ 1304bff34e3Sthurlow 1314bff34e3Sthurlow static int smbfs_open(vnode_t **, int, cred_t *, caller_context_t *); 1324bff34e3Sthurlow static int smbfs_close(vnode_t *, int, int, offset_t, cred_t *, 1334bff34e3Sthurlow caller_context_t *); 1344bff34e3Sthurlow static int smbfs_read(vnode_t *, struct uio *, int, cred_t *, 1354bff34e3Sthurlow caller_context_t *); 1364bff34e3Sthurlow static int smbfs_write(vnode_t *, struct uio *, int, cred_t *, 1374bff34e3Sthurlow caller_context_t *); 1387568150aSgwr static int smbfs_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *, 1397568150aSgwr caller_context_t *); 1404bff34e3Sthurlow static int smbfs_getattr(vnode_t *, struct vattr *, int, cred_t *, 1414bff34e3Sthurlow caller_context_t *); 1424bff34e3Sthurlow static int smbfs_setattr(vnode_t *, struct vattr *, int, cred_t *, 1434bff34e3Sthurlow caller_context_t *); 1444bff34e3Sthurlow static int smbfs_access(vnode_t *, int, int, cred_t *, caller_context_t *); 1454bff34e3Sthurlow static int smbfs_fsync(vnode_t *, int, cred_t *, caller_context_t *); 1464bff34e3Sthurlow static void smbfs_inactive(vnode_t *, cred_t *, caller_context_t *); 1474bff34e3Sthurlow static int smbfs_lookup(vnode_t *, char *, vnode_t **, struct pathname *, 1484bff34e3Sthurlow int, vnode_t *, cred_t *, caller_context_t *, 1494bff34e3Sthurlow int *, pathname_t *); 1504bff34e3Sthurlow static int smbfs_create(vnode_t *, char *, struct vattr *, enum vcexcl, 1514bff34e3Sthurlow int, vnode_t **, cred_t *, int, caller_context_t *, 1524bff34e3Sthurlow vsecattr_t *); 1534bff34e3Sthurlow static int smbfs_remove(vnode_t *, char *, cred_t *, caller_context_t *, 1544bff34e3Sthurlow int); 1554bff34e3Sthurlow static int smbfs_rename(vnode_t *, char *, vnode_t *, char *, cred_t *, 1564bff34e3Sthurlow caller_context_t *, int); 1574bff34e3Sthurlow static int smbfs_mkdir(vnode_t *, char *, struct vattr *, vnode_t **, 1584bff34e3Sthurlow cred_t *, caller_context_t *, int, vsecattr_t *); 1594bff34e3Sthurlow static int smbfs_rmdir(vnode_t *, char *, vnode_t *, cred_t *, 1604bff34e3Sthurlow caller_context_t *, int); 1614bff34e3Sthurlow static int smbfs_readdir(vnode_t *, struct uio *, cred_t *, int *, 1624bff34e3Sthurlow caller_context_t *, int); 1634bff34e3Sthurlow static int smbfs_rwlock(vnode_t *, int, caller_context_t *); 1644bff34e3Sthurlow static void smbfs_rwunlock(vnode_t *, int, caller_context_t *); 1654bff34e3Sthurlow static int smbfs_seek(vnode_t *, offset_t, offset_t *, caller_context_t *); 1664bff34e3Sthurlow static int smbfs_frlock(vnode_t *, int, struct flock64 *, int, offset_t, 1674bff34e3Sthurlow struct flk_callback *, cred_t *, caller_context_t *); 1684bff34e3Sthurlow static int smbfs_space(vnode_t *, int, struct flock64 *, int, offset_t, 1694bff34e3Sthurlow cred_t *, caller_context_t *); 1704bff34e3Sthurlow static int smbfs_pathconf(vnode_t *, int, ulong_t *, cred_t *, 1714bff34e3Sthurlow caller_context_t *); 1727568150aSgwr static int smbfs_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *, 1737568150aSgwr caller_context_t *); 1747568150aSgwr static int smbfs_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *, 1757568150aSgwr caller_context_t *); 1764bff34e3Sthurlow static int smbfs_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *, 1774bff34e3Sthurlow caller_context_t *); 1784bff34e3Sthurlow 1794bff34e3Sthurlow /* Dummy function to use until correct function is ported in */ 1804bff34e3Sthurlow int noop_vnodeop() { 1814bff34e3Sthurlow return (0); 1824bff34e3Sthurlow } 1834bff34e3Sthurlow 1844bff34e3Sthurlow struct vnodeops *smbfs_vnodeops = NULL; 1854bff34e3Sthurlow 1864bff34e3Sthurlow /* 1874bff34e3Sthurlow * Most unimplemented ops will return ENOSYS because of fs_nosys(). 1884bff34e3Sthurlow * The only ops where that won't work are ACCESS (due to open(2) 1897568150aSgwr * failures) and ... (anything else left?) 1904bff34e3Sthurlow */ 1914bff34e3Sthurlow const fs_operation_def_t smbfs_vnodeops_template[] = { 1927568150aSgwr { VOPNAME_OPEN, { .vop_open = smbfs_open } }, 1937568150aSgwr { VOPNAME_CLOSE, { .vop_close = smbfs_close } }, 1947568150aSgwr { VOPNAME_READ, { .vop_read = smbfs_read } }, 1957568150aSgwr { VOPNAME_WRITE, { .vop_write = smbfs_write } }, 1967568150aSgwr { VOPNAME_IOCTL, { .vop_ioctl = smbfs_ioctl } }, 1977568150aSgwr { VOPNAME_GETATTR, { .vop_getattr = smbfs_getattr } }, 1987568150aSgwr { VOPNAME_SETATTR, { .vop_setattr = smbfs_setattr } }, 1997568150aSgwr { VOPNAME_ACCESS, { .vop_access = smbfs_access } }, 2007568150aSgwr { VOPNAME_LOOKUP, { .vop_lookup = smbfs_lookup } }, 2017568150aSgwr { VOPNAME_CREATE, { .vop_create = smbfs_create } }, 2027568150aSgwr { VOPNAME_REMOVE, { .vop_remove = smbfs_remove } }, 2037568150aSgwr { VOPNAME_LINK, { .error = fs_nosys } }, /* smbfs_link, */ 2047568150aSgwr { VOPNAME_RENAME, { .vop_rename = smbfs_rename } }, 2057568150aSgwr { VOPNAME_MKDIR, { .vop_mkdir = smbfs_mkdir } }, 2067568150aSgwr { VOPNAME_RMDIR, { .vop_rmdir = smbfs_rmdir } }, 2077568150aSgwr { VOPNAME_READDIR, { .vop_readdir = smbfs_readdir } }, 2087568150aSgwr { VOPNAME_SYMLINK, { .error = fs_nosys } }, /* smbfs_symlink, */ 2097568150aSgwr { VOPNAME_READLINK, { .error = fs_nosys } }, /* smbfs_readlink, */ 2107568150aSgwr { VOPNAME_FSYNC, { .vop_fsync = smbfs_fsync } }, 2117568150aSgwr { VOPNAME_INACTIVE, { .vop_inactive = smbfs_inactive } }, 2127568150aSgwr { VOPNAME_FID, { .error = fs_nosys } }, /* smbfs_fid, */ 2137568150aSgwr { VOPNAME_RWLOCK, { .vop_rwlock = smbfs_rwlock } }, 2147568150aSgwr { VOPNAME_RWUNLOCK, { .vop_rwunlock = smbfs_rwunlock } }, 2157568150aSgwr { VOPNAME_SEEK, { .vop_seek = smbfs_seek } }, 2167568150aSgwr { VOPNAME_FRLOCK, { .vop_frlock = smbfs_frlock } }, 2177568150aSgwr { VOPNAME_SPACE, { .vop_space = smbfs_space } }, 2187568150aSgwr { VOPNAME_REALVP, { .error = fs_nosys } }, /* smbfs_realvp, */ 2197568150aSgwr { VOPNAME_GETPAGE, { .error = fs_nosys } }, /* smbfs_getpage, */ 2207568150aSgwr { VOPNAME_PUTPAGE, { .error = fs_nosys } }, /* smbfs_putpage, */ 2217568150aSgwr { VOPNAME_MAP, { .error = fs_nosys } }, /* smbfs_map, */ 2227568150aSgwr { VOPNAME_ADDMAP, { .error = fs_nosys } }, /* smbfs_addmap, */ 2237568150aSgwr { VOPNAME_DELMAP, { .error = fs_nosys } }, /* smbfs_delmap, */ 2247568150aSgwr { VOPNAME_DUMP, { .error = fs_nosys } }, /* smbfs_dump, */ 2257568150aSgwr { VOPNAME_PATHCONF, { .vop_pathconf = smbfs_pathconf } }, 2267568150aSgwr { VOPNAME_PAGEIO, { .error = fs_nosys } }, /* smbfs_pageio, */ 2277568150aSgwr { VOPNAME_SETSECATTR, { .vop_setsecattr = smbfs_setsecattr } }, 2287568150aSgwr { VOPNAME_GETSECATTR, { .vop_getsecattr = smbfs_getsecattr } }, 2297568150aSgwr { VOPNAME_SHRLOCK, { .vop_shrlock = smbfs_shrlock } }, 2304bff34e3Sthurlow { NULL, NULL } 2314bff34e3Sthurlow }; 2324bff34e3Sthurlow 2334bff34e3Sthurlow /* 2344bff34e3Sthurlow * XXX 2354bff34e3Sthurlow * When new and relevant functionality is enabled, we should be 2364bff34e3Sthurlow * calling vfs_set_feature() to inform callers that pieces of 2379660e5cbSJanice Chang * functionality are available, per PSARC 2007/227. 2384bff34e3Sthurlow */ 2394bff34e3Sthurlow /* ARGSUSED */ 2404bff34e3Sthurlow static int 2414bff34e3Sthurlow smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct) 2424bff34e3Sthurlow { 2434bff34e3Sthurlow struct vattr va; 2444bff34e3Sthurlow smbnode_t *np; 2454bff34e3Sthurlow vnode_t *vp; 2464bff34e3Sthurlow u_int32_t rights, rightsrcvd; 2474bff34e3Sthurlow u_int16_t fid, oldfid; 248613a2f6bSGordon Ross int oldgenid; 2494bff34e3Sthurlow struct smb_cred scred; 2504bff34e3Sthurlow smbmntinfo_t *smi; 251613a2f6bSGordon Ross smb_share_t *ssp; 2524bff34e3Sthurlow cred_t *oldcr; 2534bff34e3Sthurlow int attrcacheupdated = 0; 2544bff34e3Sthurlow int tmperror; 2554bff34e3Sthurlow int error = 0; 2564bff34e3Sthurlow 2574bff34e3Sthurlow vp = *vpp; 2584bff34e3Sthurlow np = VTOSMB(vp); 2594bff34e3Sthurlow smi = VTOSMI(vp); 260613a2f6bSGordon Ross ssp = smi->smi_share; 2614bff34e3Sthurlow 2624bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 2634bff34e3Sthurlow return (EIO); 2644bff34e3Sthurlow 2654bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 2664bff34e3Sthurlow return (EIO); 2674bff34e3Sthurlow 2684bff34e3Sthurlow if (vp->v_type != VREG && vp->v_type != VDIR) { /* XXX VLNK? */ 2694bff34e3Sthurlow SMBVDEBUG("open eacces vtype=%d\n", vp->v_type); 2704bff34e3Sthurlow return (EACCES); 2714bff34e3Sthurlow } 2724bff34e3Sthurlow 2734bff34e3Sthurlow /* 2744bff34e3Sthurlow * Get exclusive access to n_fid and related stuff. 2754bff34e3Sthurlow * No returns after this until out. 2764bff34e3Sthurlow */ 2774bff34e3Sthurlow if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp))) 2784bff34e3Sthurlow return (EINTR); 279613a2f6bSGordon Ross smb_credinit(&scred, cr); 2804bff34e3Sthurlow 28191d632c8Sgwr /* 28291d632c8Sgwr * Keep track of the vnode type at first open. 28391d632c8Sgwr * It may change later, and we need close to do 28491d632c8Sgwr * cleanup for the type we opened. Also deny 28591d632c8Sgwr * open of new types until old type is closed. 28691d632c8Sgwr * XXX: Per-open instance nodes whould help. 28791d632c8Sgwr */ 28891d632c8Sgwr if (np->n_ovtype == VNON) { 28991d632c8Sgwr ASSERT(np->n_dirrefs == 0); 29091d632c8Sgwr ASSERT(np->n_fidrefs == 0); 29191d632c8Sgwr } else if (np->n_ovtype != vp->v_type) { 29291d632c8Sgwr SMBVDEBUG("open n_ovtype=%d v_type=%d\n", 29391d632c8Sgwr np->n_ovtype, vp->v_type); 29491d632c8Sgwr error = EACCES; 29591d632c8Sgwr goto out; 29691d632c8Sgwr } 29791d632c8Sgwr 2984bff34e3Sthurlow /* 299*5ecede33SGordon Ross * Directory open. See smbfs_readvdir() 3004bff34e3Sthurlow */ 3014bff34e3Sthurlow if (vp->v_type == VDIR) { 302*5ecede33SGordon Ross if (np->n_dirseq == NULL) { 303*5ecede33SGordon Ross /* first open */ 304*5ecede33SGordon Ross error = smbfs_smb_findopen(np, "*", 1, 305*5ecede33SGordon Ross SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, 306*5ecede33SGordon Ross &scred, &np->n_dirseq); 307*5ecede33SGordon Ross if (error != 0) 308*5ecede33SGordon Ross goto out; 309*5ecede33SGordon Ross } 310*5ecede33SGordon Ross np->n_dirofs = FIRST_DIROFS; 3114bff34e3Sthurlow np->n_dirrefs++; 3124bff34e3Sthurlow goto have_fid; 3134bff34e3Sthurlow } 3144bff34e3Sthurlow 3154bff34e3Sthurlow /* 3164bff34e3Sthurlow * If caller specified O_TRUNC/FTRUNC, then be sure to set 3174bff34e3Sthurlow * FWRITE (to drive successful setattr(size=0) after open) 3184bff34e3Sthurlow */ 3194bff34e3Sthurlow if (flag & FTRUNC) 3204bff34e3Sthurlow flag |= FWRITE; 3214bff34e3Sthurlow 3224bff34e3Sthurlow /* 323613a2f6bSGordon Ross * If we already have it open, and the FID is still valid, 324613a2f6bSGordon Ross * check whether the rights are sufficient for FID reuse. 3254bff34e3Sthurlow */ 326613a2f6bSGordon Ross if (np->n_fidrefs > 0 && 327613a2f6bSGordon Ross np->n_vcgenid == ssp->ss_vcgenid) { 3284bff34e3Sthurlow int upgrade = 0; 3294bff34e3Sthurlow 3304bff34e3Sthurlow if ((flag & FWRITE) && 3314bff34e3Sthurlow !(np->n_rights & (SA_RIGHT_FILE_WRITE_DATA | 332*5ecede33SGordon Ross GENERIC_RIGHT_ALL_ACCESS | 333*5ecede33SGordon Ross GENERIC_RIGHT_WRITE_ACCESS))) 3344bff34e3Sthurlow upgrade = 1; 3354bff34e3Sthurlow if ((flag & FREAD) && 3364bff34e3Sthurlow !(np->n_rights & (SA_RIGHT_FILE_READ_DATA | 337*5ecede33SGordon Ross GENERIC_RIGHT_ALL_ACCESS | 338*5ecede33SGordon Ross GENERIC_RIGHT_READ_ACCESS))) 3394bff34e3Sthurlow upgrade = 1; 3404bff34e3Sthurlow if (!upgrade) { 3414bff34e3Sthurlow /* 3424bff34e3Sthurlow * the existing open is good enough 3434bff34e3Sthurlow */ 3444bff34e3Sthurlow np->n_fidrefs++; 3454bff34e3Sthurlow goto have_fid; 3464bff34e3Sthurlow } 3474bff34e3Sthurlow } 3484bff34e3Sthurlow rights = np->n_fidrefs ? np->n_rights : 0; 3494bff34e3Sthurlow 3504bff34e3Sthurlow /* 3514bff34e3Sthurlow * we always ask for READ_CONTROL so we can always get the 35291d632c8Sgwr * owner/group IDs to satisfy a stat. Ditto attributes. 3534bff34e3Sthurlow * XXX: verify that works with "drop boxes" 3544bff34e3Sthurlow */ 35591d632c8Sgwr rights |= (STD_RIGHT_READ_CONTROL_ACCESS | 35691d632c8Sgwr SA_RIGHT_FILE_READ_ATTRIBUTES); 3574bff34e3Sthurlow if ((flag & FREAD)) 3584bff34e3Sthurlow rights |= SA_RIGHT_FILE_READ_DATA; 3594bff34e3Sthurlow if ((flag & FWRITE)) 3604bff34e3Sthurlow rights |= SA_RIGHT_FILE_APPEND_DATA | SA_RIGHT_FILE_WRITE_DATA; 3614bff34e3Sthurlow 3624bff34e3Sthurlow /* XXX: open gets the current size, but we don't use it. */ 3634bff34e3Sthurlow error = smbfs_smb_open(np, rights, &scred, &attrcacheupdated, &fid, 3644bff34e3Sthurlow NULL, 0, 0, NULL, &rightsrcvd); 3654bff34e3Sthurlow if (error) 3664bff34e3Sthurlow goto out; 3674bff34e3Sthurlow 3684bff34e3Sthurlow /* 3694bff34e3Sthurlow * We have a new FID and access rights. 3704bff34e3Sthurlow */ 3714bff34e3Sthurlow oldfid = np->n_fid; 372613a2f6bSGordon Ross oldgenid = np->n_vcgenid; 3734bff34e3Sthurlow np->n_fid = fid; 374613a2f6bSGordon Ross np->n_vcgenid = ssp->ss_vcgenid; 3754bff34e3Sthurlow np->n_rights = rightsrcvd; 3764bff34e3Sthurlow np->n_fidrefs++; 377613a2f6bSGordon Ross if (np->n_fidrefs > 1 && 378613a2f6bSGordon Ross oldgenid == ssp->ss_vcgenid) { 3794bff34e3Sthurlow /* 3804bff34e3Sthurlow * We already had it open (presumably because 3814bff34e3Sthurlow * it was open with insufficient rights.) 3824bff34e3Sthurlow * Close old wire-open. 3834bff34e3Sthurlow */ 384613a2f6bSGordon Ross tmperror = smbfs_smb_close(ssp, 3854bff34e3Sthurlow oldfid, &np->n_mtime, &scred); 3864bff34e3Sthurlow if (tmperror) 3874bff34e3Sthurlow SMBVDEBUG("error %d closing %s\n", 3884bff34e3Sthurlow tmperror, np->n_rpath); 3894bff34e3Sthurlow } 3904bff34e3Sthurlow 3914bff34e3Sthurlow /* 3924bff34e3Sthurlow * This thread did the open. 3934bff34e3Sthurlow * Save our credentials too. 3944bff34e3Sthurlow */ 3954bff34e3Sthurlow mutex_enter(&np->r_statelock); 3964bff34e3Sthurlow oldcr = np->r_cred; 3974bff34e3Sthurlow np->r_cred = cr; 3984bff34e3Sthurlow crhold(cr); 3994bff34e3Sthurlow if (oldcr) 4004bff34e3Sthurlow crfree(oldcr); 4014bff34e3Sthurlow mutex_exit(&np->r_statelock); 4024bff34e3Sthurlow 4034bff34e3Sthurlow have_fid: 40491d632c8Sgwr /* 40591d632c8Sgwr * Keep track of the vnode type at first open. 40691d632c8Sgwr * (see comments above) 40791d632c8Sgwr */ 40891d632c8Sgwr if (np->n_ovtype == VNON) 40991d632c8Sgwr np->n_ovtype = vp->v_type; 4104bff34e3Sthurlow 41191d632c8Sgwr /* Get attributes (maybe). */ 4124bff34e3Sthurlow 4134bff34e3Sthurlow /* Darwin (derived) code. */ 4144bff34e3Sthurlow 4154bff34e3Sthurlow va.va_mask = AT_MTIME; 4164bff34e3Sthurlow if (np->n_flag & NMODIFIED) 4174bff34e3Sthurlow smbfs_attr_cacheremove(np); 4184bff34e3Sthurlow 4194bff34e3Sthurlow /* 4204bff34e3Sthurlow * Try to get attributes, but don't bail on error. 4214bff34e3Sthurlow * We already hold r_lkserlock/reader so note: 4224bff34e3Sthurlow * this call will recursively take r_lkserlock. 4234bff34e3Sthurlow */ 4244bff34e3Sthurlow tmperror = smbfsgetattr(vp, &va, cr); 4254bff34e3Sthurlow if (tmperror) 4264bff34e3Sthurlow SMBERROR("getattr failed, error=%d", tmperror); 4274bff34e3Sthurlow else 4284bff34e3Sthurlow np->n_mtime.tv_sec = va.va_mtime.tv_sec; 4294bff34e3Sthurlow 4304bff34e3Sthurlow out: 4314bff34e3Sthurlow smb_credrele(&scred); 4324bff34e3Sthurlow smbfs_rw_exit(&np->r_lkserlock); 4334bff34e3Sthurlow return (error); 4344bff34e3Sthurlow } 4354bff34e3Sthurlow 4364bff34e3Sthurlow /*ARGSUSED*/ 4374bff34e3Sthurlow static int 4384bff34e3Sthurlow smbfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr, 4394bff34e3Sthurlow caller_context_t *ct) 4404bff34e3Sthurlow { 4414bff34e3Sthurlow smbnode_t *np; 442613a2f6bSGordon Ross smbmntinfo_t *smi; 443613a2f6bSGordon Ross smb_share_t *ssp; 4444bff34e3Sthurlow int error = 0; 4454bff34e3Sthurlow struct smb_cred scred; 4464bff34e3Sthurlow 4474bff34e3Sthurlow np = VTOSMB(vp); 448613a2f6bSGordon Ross smi = VTOSMI(vp); 449613a2f6bSGordon Ross ssp = smi->smi_share; 4504bff34e3Sthurlow 4514bff34e3Sthurlow /* 4524bff34e3Sthurlow * Don't "bail out" for VFS_UNMOUNTED here, 4534bff34e3Sthurlow * as we want to do cleanup, etc. 4544bff34e3Sthurlow */ 4554bff34e3Sthurlow 4564bff34e3Sthurlow /* 4574bff34e3Sthurlow * zone_enter(2) prevents processes from changing zones with SMBFS files 4584bff34e3Sthurlow * open; if we happen to get here from the wrong zone we can't do 4594bff34e3Sthurlow * anything over the wire. 4604bff34e3Sthurlow */ 4614bff34e3Sthurlow if (VTOSMI(vp)->smi_zone != curproc->p_zone) { 4624bff34e3Sthurlow /* 4634bff34e3Sthurlow * We could attempt to clean up locks, except we're sure 4644bff34e3Sthurlow * that the current process didn't acquire any locks on 4654bff34e3Sthurlow * the file: any attempt to lock a file belong to another zone 4664bff34e3Sthurlow * will fail, and one can't lock an SMBFS file and then change 4674bff34e3Sthurlow * zones, as that fails too. 4684bff34e3Sthurlow * 4694bff34e3Sthurlow * Returning an error here is the sane thing to do. A 4704bff34e3Sthurlow * subsequent call to VN_RELE() which translates to a 4714bff34e3Sthurlow * smbfs_inactive() will clean up state: if the zone of the 4724bff34e3Sthurlow * vnode's origin is still alive and kicking, an async worker 4734bff34e3Sthurlow * thread will handle the request (from the correct zone), and 4744bff34e3Sthurlow * everything (minus the final smbfs_getattr_otw() call) should 4754bff34e3Sthurlow * be OK. If the zone is going away smbfs_async_inactive() will 4764bff34e3Sthurlow * throw away cached pages inline. 4774bff34e3Sthurlow */ 4784bff34e3Sthurlow return (EIO); 4794bff34e3Sthurlow } 4804bff34e3Sthurlow 4814bff34e3Sthurlow /* 4824bff34e3Sthurlow * If we are using local locking for this filesystem, then 4834bff34e3Sthurlow * release all of the SYSV style record locks. Otherwise, 4844bff34e3Sthurlow * we are doing network locking and we need to release all 4854bff34e3Sthurlow * of the network locks. All of the locks held by this 4864bff34e3Sthurlow * process on this file are released no matter what the 4874bff34e3Sthurlow * incoming reference count is. 4884bff34e3Sthurlow */ 4894bff34e3Sthurlow if (VTOSMI(vp)->smi_flags & SMI_LLOCK) { 490613a2f6bSGordon Ross pid_t pid = ddi_get_pid(); 491613a2f6bSGordon Ross cleanlocks(vp, pid, 0); 492613a2f6bSGordon Ross cleanshares(vp, pid); 4934bff34e3Sthurlow } 4944bff34e3Sthurlow 4954bff34e3Sthurlow if (count > 1) 4964bff34e3Sthurlow return (0); 4974bff34e3Sthurlow /* 4984bff34e3Sthurlow * OK, do "last close" stuff. 4994bff34e3Sthurlow */ 5004bff34e3Sthurlow 5014bff34e3Sthurlow 5024bff34e3Sthurlow /* 5034bff34e3Sthurlow * Do the CIFS close. 5044bff34e3Sthurlow * Darwin code 5054bff34e3Sthurlow */ 5064bff34e3Sthurlow 5074bff34e3Sthurlow /* 5084bff34e3Sthurlow * Exclusive lock for modifying n_fid stuff. 5094bff34e3Sthurlow * Don't want this one ever interruptible. 5104bff34e3Sthurlow */ 5114bff34e3Sthurlow (void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0); 512613a2f6bSGordon Ross smb_credinit(&scred, cr); 5134bff34e3Sthurlow 5144bff34e3Sthurlow error = 0; 51591d632c8Sgwr 51691d632c8Sgwr /* 51791d632c8Sgwr * Note that vp->v_type may change if a remote node 51891d632c8Sgwr * is deleted and recreated as a different type, and 51991d632c8Sgwr * our getattr may change v_type accordingly. 52091d632c8Sgwr * Now use n_ovtype to keep track of the v_type 52191d632c8Sgwr * we had during open (see comments above). 52291d632c8Sgwr */ 52391d632c8Sgwr if (np->n_ovtype == VDIR) { 5244bff34e3Sthurlow struct smbfs_fctx *fctx; 5254bff34e3Sthurlow ASSERT(np->n_dirrefs > 0); 5264bff34e3Sthurlow if (--np->n_dirrefs) 5274bff34e3Sthurlow goto out; 5284bff34e3Sthurlow if ((fctx = np->n_dirseq) != NULL) { 5294bff34e3Sthurlow np->n_dirseq = NULL; 530*5ecede33SGordon Ross np->n_dirofs = 0; 5314bff34e3Sthurlow error = smbfs_smb_findclose(fctx, &scred); 5324bff34e3Sthurlow } 5334bff34e3Sthurlow } else { 5344bff34e3Sthurlow uint16_t ofid; 5354bff34e3Sthurlow ASSERT(np->n_fidrefs > 0); 5364bff34e3Sthurlow if (--np->n_fidrefs) 5374bff34e3Sthurlow goto out; 5384bff34e3Sthurlow if ((ofid = np->n_fid) != SMB_FID_UNUSED) { 5394bff34e3Sthurlow np->n_fid = SMB_FID_UNUSED; 540613a2f6bSGordon Ross /* After reconnect, n_fid is invalid */ 541613a2f6bSGordon Ross if (np->n_vcgenid == ssp->ss_vcgenid) { 542613a2f6bSGordon Ross error = smbfs_smb_close( 543613a2f6bSGordon Ross ssp, ofid, NULL, &scred); 544613a2f6bSGordon Ross } 5454bff34e3Sthurlow } 5464bff34e3Sthurlow } 5474bff34e3Sthurlow if (error) { 5484bff34e3Sthurlow SMBERROR("error %d closing %s\n", 5494bff34e3Sthurlow error, np->n_rpath); 5504bff34e3Sthurlow } 5514bff34e3Sthurlow 55291d632c8Sgwr /* Allow next open to use any v_type. */ 55391d632c8Sgwr np->n_ovtype = VNON; 55491d632c8Sgwr 5554bff34e3Sthurlow if (np->n_flag & NATTRCHANGED) 5564bff34e3Sthurlow smbfs_attr_cacheremove(np); 5574bff34e3Sthurlow 5584bff34e3Sthurlow out: 5594bff34e3Sthurlow smb_credrele(&scred); 5604bff34e3Sthurlow smbfs_rw_exit(&np->r_lkserlock); 5614bff34e3Sthurlow 5624bff34e3Sthurlow /* don't return any errors */ 5634bff34e3Sthurlow return (0); 5644bff34e3Sthurlow } 5654bff34e3Sthurlow 5664bff34e3Sthurlow /* ARGSUSED */ 5674bff34e3Sthurlow static int 5684bff34e3Sthurlow smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr, 5694bff34e3Sthurlow caller_context_t *ct) 5704bff34e3Sthurlow { 5719c9af259SGordon Ross struct smb_cred scred; 5729c9af259SGordon Ross struct vattr va; 573613a2f6bSGordon Ross smbnode_t *np; 574613a2f6bSGordon Ross smbmntinfo_t *smi; 575613a2f6bSGordon Ross smb_share_t *ssp; 5769c9af259SGordon Ross offset_t endoff; 5779c9af259SGordon Ross ssize_t past_eof; 5789c9af259SGordon Ross int error; 5794bff34e3Sthurlow 5804bff34e3Sthurlow np = VTOSMB(vp); 5814bff34e3Sthurlow smi = VTOSMI(vp); 582613a2f6bSGordon Ross ssp = smi->smi_share; 5834bff34e3Sthurlow 5844bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 5854bff34e3Sthurlow return (EIO); 5864bff34e3Sthurlow 5874bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 5884bff34e3Sthurlow return (EIO); 5894bff34e3Sthurlow 5904bff34e3Sthurlow ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER)); 5914bff34e3Sthurlow 5924bff34e3Sthurlow if (vp->v_type != VREG) 5934bff34e3Sthurlow return (EISDIR); 5944bff34e3Sthurlow 5954bff34e3Sthurlow if (uiop->uio_resid == 0) 5964bff34e3Sthurlow return (0); 5974bff34e3Sthurlow 5984bff34e3Sthurlow /* 5994bff34e3Sthurlow * Like NFS3, just check for 63-bit overflow. 6004bff34e3Sthurlow * Our SMB layer takes care to return EFBIG 6014bff34e3Sthurlow * when it has to fallback to a 32-bit call. 6024bff34e3Sthurlow */ 603613a2f6bSGordon Ross endoff = uiop->uio_loffset + uiop->uio_resid; 604613a2f6bSGordon Ross if (uiop->uio_loffset < 0 || endoff < 0) 6054bff34e3Sthurlow return (EINVAL); 6064bff34e3Sthurlow 6074bff34e3Sthurlow /* get vnode attributes from server */ 6084bff34e3Sthurlow va.va_mask = AT_SIZE | AT_MTIME; 6094bff34e3Sthurlow if (error = smbfsgetattr(vp, &va, cr)) 6109c9af259SGordon Ross return (error); 6114bff34e3Sthurlow 6129c9af259SGordon Ross /* Update mtime with mtime from server here? */ 6139c9af259SGordon Ross 6149c9af259SGordon Ross /* if offset is beyond EOF, read nothing */ 6159c9af259SGordon Ross if (uiop->uio_loffset >= va.va_size) 6169c9af259SGordon Ross return (0); 6174bff34e3Sthurlow 6184bff34e3Sthurlow /* 6199c9af259SGordon Ross * Limit the read to the remaining file size. 6209c9af259SGordon Ross * Do this by temporarily reducing uio_resid 6219c9af259SGordon Ross * by the amount the lies beyoned the EOF. 6224bff34e3Sthurlow */ 6239c9af259SGordon Ross if (endoff > va.va_size) { 6249c9af259SGordon Ross past_eof = (ssize_t)(endoff - va.va_size); 6259c9af259SGordon Ross uiop->uio_resid -= past_eof; 6269c9af259SGordon Ross } else 6279c9af259SGordon Ross past_eof = 0; 6289c9af259SGordon Ross 6299c9af259SGordon Ross /* Shared lock for n_fid use in smb_rwuio */ 6309c9af259SGordon Ross if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) 6319c9af259SGordon Ross return (EINTR); 632613a2f6bSGordon Ross smb_credinit(&scred, cr); 6334bff34e3Sthurlow 634613a2f6bSGordon Ross /* After reconnect, n_fid is invalid */ 635613a2f6bSGordon Ross if (np->n_vcgenid != ssp->ss_vcgenid) 636613a2f6bSGordon Ross error = ESTALE; 637613a2f6bSGordon Ross else 638613a2f6bSGordon Ross error = smb_rwuio(ssp, np->n_fid, UIO_READ, 639613a2f6bSGordon Ross uiop, &scred, smb_timo_read); 6409c9af259SGordon Ross 6419c9af259SGordon Ross smb_credrele(&scred); 6424bff34e3Sthurlow smbfs_rw_exit(&np->r_lkserlock); 6434bff34e3Sthurlow 6449c9af259SGordon Ross /* undo adjustment of resid */ 6459c9af259SGordon Ross uiop->uio_resid += past_eof; 6469c9af259SGordon Ross 6479c9af259SGordon Ross return (error); 6484bff34e3Sthurlow } 6494bff34e3Sthurlow 6504bff34e3Sthurlow 6514bff34e3Sthurlow /* ARGSUSED */ 6524bff34e3Sthurlow static int 6534bff34e3Sthurlow smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr, 6544bff34e3Sthurlow caller_context_t *ct) 6554bff34e3Sthurlow { 6569c9af259SGordon Ross struct smb_cred scred; 6579c9af259SGordon Ross struct vattr va; 658613a2f6bSGordon Ross smbnode_t *np; 659613a2f6bSGordon Ross smbmntinfo_t *smi; 660613a2f6bSGordon Ross smb_share_t *ssp; 6619c9af259SGordon Ross offset_t endoff, limit; 6629c9af259SGordon Ross ssize_t past_limit; 6639c9af259SGordon Ross int error, timo; 6644bff34e3Sthurlow 6654bff34e3Sthurlow np = VTOSMB(vp); 6664bff34e3Sthurlow smi = VTOSMI(vp); 667613a2f6bSGordon Ross ssp = smi->smi_share; 6684bff34e3Sthurlow 6694bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 6704bff34e3Sthurlow return (EIO); 6714bff34e3Sthurlow 6724bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 6734bff34e3Sthurlow return (EIO); 6744bff34e3Sthurlow 6754bff34e3Sthurlow ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_WRITER)); 6764bff34e3Sthurlow 6774bff34e3Sthurlow if (vp->v_type != VREG) 6784bff34e3Sthurlow return (EISDIR); 6794bff34e3Sthurlow 6804bff34e3Sthurlow if (uiop->uio_resid == 0) 6814bff34e3Sthurlow return (0); 6824bff34e3Sthurlow 6839c9af259SGordon Ross /* 6849c9af259SGordon Ross * Handle ioflag bits: (FAPPEND|FSYNC|FDSYNC) 6859c9af259SGordon Ross */ 6869c9af259SGordon Ross if (ioflag & (FAPPEND | FSYNC)) { 6879c9af259SGordon Ross if (np->n_flag & NMODIFIED) { 6889c9af259SGordon Ross smbfs_attr_cacheremove(np); 6899c9af259SGordon Ross /* XXX: smbfs_vinvalbuf? */ 6909c9af259SGordon Ross } 6919c9af259SGordon Ross } 6929c9af259SGordon Ross if (ioflag & FAPPEND) { 6939c9af259SGordon Ross /* 6949c9af259SGordon Ross * File size can be changed by another client 6959c9af259SGordon Ross */ 6969c9af259SGordon Ross va.va_mask = AT_SIZE; 6979c9af259SGordon Ross if (error = smbfsgetattr(vp, &va, cr)) 6989c9af259SGordon Ross return (error); 6999c9af259SGordon Ross uiop->uio_loffset = va.va_size; 7009c9af259SGordon Ross } 7014bff34e3Sthurlow 7029c9af259SGordon Ross /* 7039c9af259SGordon Ross * Like NFS3, just check for 63-bit overflow. 7049c9af259SGordon Ross */ 7059c9af259SGordon Ross endoff = uiop->uio_loffset + uiop->uio_resid; 7069c9af259SGordon Ross if (uiop->uio_loffset < 0 || endoff < 0) 7079c9af259SGordon Ross return (EINVAL); 7084bff34e3Sthurlow 7094bff34e3Sthurlow /* 7109c9af259SGordon Ross * Check to make sure that the process will not exceed 7119c9af259SGordon Ross * its limit on file size. It is okay to write up to 7129c9af259SGordon Ross * the limit, but not beyond. Thus, the write which 7139c9af259SGordon Ross * reaches the limit will be short and the next write 7149c9af259SGordon Ross * will return an error. 7159c9af259SGordon Ross * 7169c9af259SGordon Ross * So if we're starting at or beyond the limit, EFBIG. 7179c9af259SGordon Ross * Otherwise, temporarily reduce resid to the amount 7189c9af259SGordon Ross * the falls after the limit. 7194bff34e3Sthurlow */ 7209c9af259SGordon Ross limit = uiop->uio_llimit; 7219c9af259SGordon Ross if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T) 7229c9af259SGordon Ross limit = MAXOFFSET_T; 7239c9af259SGordon Ross if (uiop->uio_loffset >= limit) 7249c9af259SGordon Ross return (EFBIG); 7259c9af259SGordon Ross if (endoff > limit) { 7269c9af259SGordon Ross past_limit = (ssize_t)(endoff - limit); 7279c9af259SGordon Ross uiop->uio_resid -= past_limit; 7289c9af259SGordon Ross } else 7299c9af259SGordon Ross past_limit = 0; 7309c9af259SGordon Ross 7319c9af259SGordon Ross /* Timeout: longer for append. */ 7329c9af259SGordon Ross timo = smb_timo_write; 7339c9af259SGordon Ross if (endoff > np->n_size) 7349c9af259SGordon Ross timo = smb_timo_append; 7359c9af259SGordon Ross 7369c9af259SGordon Ross /* Shared lock for n_fid use in smb_rwuio */ 7379c9af259SGordon Ross if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) 7389c9af259SGordon Ross return (EINTR); 739613a2f6bSGordon Ross smb_credinit(&scred, cr); 7404bff34e3Sthurlow 741613a2f6bSGordon Ross /* After reconnect, n_fid is invalid */ 742613a2f6bSGordon Ross if (np->n_vcgenid != ssp->ss_vcgenid) 743613a2f6bSGordon Ross error = ESTALE; 744613a2f6bSGordon Ross else 745613a2f6bSGordon Ross error = smb_rwuio(ssp, np->n_fid, UIO_WRITE, 746613a2f6bSGordon Ross uiop, &scred, timo); 7479c9af259SGordon Ross 7489c9af259SGordon Ross if (error == 0) { 7499c9af259SGordon Ross mutex_enter(&np->r_statelock); 7509c9af259SGordon Ross np->n_flag |= (NFLUSHWIRE | NATTRCHANGED); 7519c9af259SGordon Ross if (uiop->uio_loffset > (offset_t)np->n_size) 7529c9af259SGordon Ross np->n_size = (len_t)uiop->uio_loffset; 7539c9af259SGordon Ross mutex_exit(&np->r_statelock); 7549c9af259SGordon Ross if (ioflag & (FSYNC|FDSYNC)) { 7559c9af259SGordon Ross /* Don't error the I/O if this fails. */ 7569c9af259SGordon Ross (void) smbfs_smb_flush(np, &scred); 7579c9af259SGordon Ross } 7589c9af259SGordon Ross } 7599c9af259SGordon Ross 7609c9af259SGordon Ross smb_credrele(&scred); 7614bff34e3Sthurlow smbfs_rw_exit(&np->r_lkserlock); 7624bff34e3Sthurlow 7639c9af259SGordon Ross /* undo adjustment of resid */ 7649c9af259SGordon Ross uiop->uio_resid += past_limit; 7659c9af259SGordon Ross 7669c9af259SGordon Ross return (error); 7674bff34e3Sthurlow } 7684bff34e3Sthurlow 7694bff34e3Sthurlow 7707568150aSgwr /* ARGSUSED */ 7717568150aSgwr static int 7727568150aSgwr smbfs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag, 7737568150aSgwr cred_t *cr, int *rvalp, caller_context_t *ct) 7747568150aSgwr { 7757568150aSgwr int error; 7767568150aSgwr smbmntinfo_t *smi; 7777568150aSgwr 7787568150aSgwr smi = VTOSMI(vp); 7797568150aSgwr 7807568150aSgwr if (curproc->p_zone != smi->smi_zone) 7817568150aSgwr return (EIO); 7827568150aSgwr 7837568150aSgwr if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 7847568150aSgwr return (EIO); 7857568150aSgwr 7867568150aSgwr switch (cmd) { 7877568150aSgwr /* First three from ZFS. XXX - need these? */ 7887568150aSgwr 7897568150aSgwr case _FIOFFS: 7907568150aSgwr error = smbfs_fsync(vp, 0, cr, ct); 7917568150aSgwr break; 7927568150aSgwr 7937568150aSgwr /* 7947568150aSgwr * The following two ioctls are used by bfu. 7957568150aSgwr * Silently ignore to avoid bfu errors. 7967568150aSgwr */ 7977568150aSgwr case _FIOGDIO: 7987568150aSgwr case _FIOSDIO: 7997568150aSgwr error = 0; 8007568150aSgwr break; 8017568150aSgwr 8027568150aSgwr #ifdef NOT_YET /* XXX - from the NFS code. */ 8037568150aSgwr case _FIODIRECTIO: 8047568150aSgwr error = smbfs_directio(vp, (int)arg, cr); 8057568150aSgwr #endif 8067568150aSgwr 8077568150aSgwr /* 8087568150aSgwr * Allow get/set with "raw" security descriptor (SD) data. 8097568150aSgwr * Useful for testing, diagnosing idmap problems, etc. 8107568150aSgwr */ 8117568150aSgwr case SMBFSIO_GETSD: 8127568150aSgwr error = smbfs_ioc_getsd(vp, arg, flag, cr); 8137568150aSgwr break; 8147568150aSgwr 8157568150aSgwr case SMBFSIO_SETSD: 8167568150aSgwr error = smbfs_ioc_setsd(vp, arg, flag, cr); 8177568150aSgwr break; 8187568150aSgwr 8197568150aSgwr default: 8207568150aSgwr error = ENOTTY; 8217568150aSgwr break; 8227568150aSgwr } 8237568150aSgwr 8247568150aSgwr return (error); 8257568150aSgwr } 8267568150aSgwr 8277568150aSgwr 8284bff34e3Sthurlow /* 8294bff34e3Sthurlow * Return either cached or remote attributes. If get remote attr 8304bff34e3Sthurlow * use them to check and invalidate caches, then cache the new attributes. 8314bff34e3Sthurlow * 8324bff34e3Sthurlow * XXX 8334bff34e3Sthurlow * This op should eventually support PSARC 2007/315, Extensible Attribute 8344bff34e3Sthurlow * Interfaces, for richer metadata. 8354bff34e3Sthurlow */ 8364bff34e3Sthurlow /* ARGSUSED */ 8374bff34e3Sthurlow static int 8384bff34e3Sthurlow smbfs_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr, 8394bff34e3Sthurlow caller_context_t *ct) 8404bff34e3Sthurlow { 8414bff34e3Sthurlow smbnode_t *np; 8424bff34e3Sthurlow smbmntinfo_t *smi; 8434bff34e3Sthurlow 8444bff34e3Sthurlow smi = VTOSMI(vp); 8454bff34e3Sthurlow 8464bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 8474bff34e3Sthurlow return (EIO); 8484bff34e3Sthurlow 8494bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 8504bff34e3Sthurlow return (EIO); 8514bff34e3Sthurlow 8524bff34e3Sthurlow /* 8534bff34e3Sthurlow * If it has been specified that the return value will 8544bff34e3Sthurlow * just be used as a hint, and we are only being asked 8554bff34e3Sthurlow * for size, fsid or rdevid, then return the client's 8564bff34e3Sthurlow * notion of these values without checking to make sure 8574bff34e3Sthurlow * that the attribute cache is up to date. 8584bff34e3Sthurlow * The whole point is to avoid an over the wire GETATTR 8594bff34e3Sthurlow * call. 8604bff34e3Sthurlow */ 8614bff34e3Sthurlow np = VTOSMB(vp); 8624bff34e3Sthurlow if (flags & ATTR_HINT) { 8634bff34e3Sthurlow if (vap->va_mask == 8644bff34e3Sthurlow (vap->va_mask & (AT_SIZE | AT_FSID | AT_RDEV))) { 8654bff34e3Sthurlow mutex_enter(&np->r_statelock); 8664bff34e3Sthurlow if (vap->va_mask | AT_SIZE) 8674bff34e3Sthurlow vap->va_size = np->r_size; 8684bff34e3Sthurlow if (vap->va_mask | AT_FSID) 8694bff34e3Sthurlow vap->va_fsid = np->r_attr.va_fsid; 8704bff34e3Sthurlow if (vap->va_mask | AT_RDEV) 8714bff34e3Sthurlow vap->va_rdev = np->r_attr.va_rdev; 8724bff34e3Sthurlow mutex_exit(&np->r_statelock); 8734bff34e3Sthurlow return (0); 8744bff34e3Sthurlow } 8754bff34e3Sthurlow } 8764bff34e3Sthurlow 8774bff34e3Sthurlow 8784bff34e3Sthurlow return (smbfsgetattr(vp, vap, cr)); 8794bff34e3Sthurlow } 8804bff34e3Sthurlow 8814bff34e3Sthurlow /* 8824bff34e3Sthurlow * Mostly from Darwin smbfs_getattr() 8834bff34e3Sthurlow */ 8844bff34e3Sthurlow int 8854bff34e3Sthurlow smbfsgetattr(vnode_t *vp, struct vattr *vap, cred_t *cr) 8864bff34e3Sthurlow { 8874bff34e3Sthurlow int error; 8884bff34e3Sthurlow smbnode_t *np; 8894bff34e3Sthurlow struct smb_cred scred; 8904bff34e3Sthurlow struct smbfattr fattr; 8914bff34e3Sthurlow 8924bff34e3Sthurlow ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone); 8934bff34e3Sthurlow 8944bff34e3Sthurlow np = VTOSMB(vp); 8954bff34e3Sthurlow 8964bff34e3Sthurlow /* 8974bff34e3Sthurlow * If we've got cached attributes, we're done, otherwise go 8984bff34e3Sthurlow * to the server to get attributes, which will update the cache 8994bff34e3Sthurlow * in the process. 9004bff34e3Sthurlow * 9014bff34e3Sthurlow * This section from Darwin smbfs_getattr, 9024bff34e3Sthurlow * but then modified a lot. 9034bff34e3Sthurlow */ 9044bff34e3Sthurlow error = smbfs_attr_cachelookup(vp, vap); 9054bff34e3Sthurlow if (error != ENOENT) 9064bff34e3Sthurlow return (error); 9074bff34e3Sthurlow 9084bff34e3Sthurlow /* Shared lock for (possible) n_fid use. */ 9094bff34e3Sthurlow if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) 9104bff34e3Sthurlow return (EINTR); 911613a2f6bSGordon Ross smb_credinit(&scred, cr); 9124bff34e3Sthurlow 91391d632c8Sgwr bzero(&fattr, sizeof (fattr)); 9144bff34e3Sthurlow error = smbfs_smb_getfattr(np, &fattr, &scred); 9154bff34e3Sthurlow 9164bff34e3Sthurlow smb_credrele(&scred); 9174bff34e3Sthurlow smbfs_rw_exit(&np->r_lkserlock); 9184bff34e3Sthurlow 9194bff34e3Sthurlow if (!error) { 9204bff34e3Sthurlow smbfs_attr_cacheenter(vp, &fattr); 9214bff34e3Sthurlow error = smbfs_attr_cachelookup(vp, vap); 9224bff34e3Sthurlow } 9234bff34e3Sthurlow return (error); 9244bff34e3Sthurlow } 9254bff34e3Sthurlow 9264bff34e3Sthurlow /* 9274bff34e3Sthurlow * XXX 9284bff34e3Sthurlow * This op should eventually support PSARC 2007/315, Extensible Attribute 9294bff34e3Sthurlow * Interfaces, for richer metadata. 9304bff34e3Sthurlow */ 9314bff34e3Sthurlow /*ARGSUSED4*/ 9324bff34e3Sthurlow static int 9334bff34e3Sthurlow smbfs_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr, 9344bff34e3Sthurlow caller_context_t *ct) 9354bff34e3Sthurlow { 9364bff34e3Sthurlow int error; 9374bff34e3Sthurlow uint_t mask; 9384bff34e3Sthurlow struct vattr oldva; 9394bff34e3Sthurlow smbmntinfo_t *smi; 9404bff34e3Sthurlow 9414bff34e3Sthurlow smi = VTOSMI(vp); 9424bff34e3Sthurlow 9434bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 9444bff34e3Sthurlow return (EIO); 9454bff34e3Sthurlow 9464bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 9474bff34e3Sthurlow return (EIO); 9484bff34e3Sthurlow 9494bff34e3Sthurlow mask = vap->va_mask; 9504bff34e3Sthurlow if (mask & AT_NOSET) 9514bff34e3Sthurlow return (EINVAL); 9524bff34e3Sthurlow 9534bff34e3Sthurlow oldva.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID; 9544bff34e3Sthurlow error = smbfsgetattr(vp, &oldva, cr); 9554bff34e3Sthurlow if (error) 9564bff34e3Sthurlow return (error); 9574bff34e3Sthurlow 9584bff34e3Sthurlow error = secpolicy_vnode_setattr(cr, vp, vap, &oldva, flags, 9594bff34e3Sthurlow smbfs_accessx, vp); 9604bff34e3Sthurlow if (error) 9614bff34e3Sthurlow return (error); 9624bff34e3Sthurlow 9634bff34e3Sthurlow return (smbfssetattr(vp, vap, flags, cr)); 9644bff34e3Sthurlow } 9654bff34e3Sthurlow 9664bff34e3Sthurlow /* 9674bff34e3Sthurlow * Mostly from Darwin smbfs_setattr() 9684bff34e3Sthurlow * but then modified a lot. 9694bff34e3Sthurlow */ 9704bff34e3Sthurlow /* ARGSUSED */ 9714bff34e3Sthurlow static int 9724bff34e3Sthurlow smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr) 9734bff34e3Sthurlow { 9744bff34e3Sthurlow int error = 0; 9754bff34e3Sthurlow smbnode_t *np = VTOSMB(vp); 9764bff34e3Sthurlow smbmntinfo_t *smi = VTOSMI(vp); 9774bff34e3Sthurlow uint_t mask = vap->va_mask; 9784bff34e3Sthurlow struct timespec *mtime, *atime; 9794bff34e3Sthurlow struct smb_cred scred; 9804bff34e3Sthurlow int cerror, modified = 0; 9814bff34e3Sthurlow unsigned short fid; 9824bff34e3Sthurlow int have_fid = 0; 9834bff34e3Sthurlow uint32_t rights = 0; 9844bff34e3Sthurlow 9854bff34e3Sthurlow ASSERT(curproc->p_zone == smi->smi_zone); 9864bff34e3Sthurlow 98791d632c8Sgwr /* 98891d632c8Sgwr * There are no settable attributes on the XATTR dir, 98991d632c8Sgwr * so just silently ignore these. On XATTR files, 99091d632c8Sgwr * you can set the size but nothing else. 99191d632c8Sgwr */ 99291d632c8Sgwr if (vp->v_flag & V_XATTRDIR) 99391d632c8Sgwr return (0); 99491d632c8Sgwr if (np->n_flag & N_XATTR) { 99591d632c8Sgwr if (mask & AT_TIMES) 99691d632c8Sgwr SMBVDEBUG("ignore set time on xattr\n"); 99791d632c8Sgwr mask &= AT_SIZE; 99891d632c8Sgwr } 99991d632c8Sgwr 10004bff34e3Sthurlow /* 10014bff34e3Sthurlow * If our caller is trying to set multiple attributes, they 10024bff34e3Sthurlow * can make no assumption about what order they are done in. 10034bff34e3Sthurlow * Here we try to do them in order of decreasing likelihood 10044bff34e3Sthurlow * of failure, just to minimize the chance we'll wind up 10054bff34e3Sthurlow * with a partially complete request. 10064bff34e3Sthurlow */ 10074bff34e3Sthurlow 10084bff34e3Sthurlow /* Shared lock for (possible) n_fid use. */ 10094bff34e3Sthurlow if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) 10104bff34e3Sthurlow return (EINTR); 1011613a2f6bSGordon Ross smb_credinit(&scred, cr); 10124bff34e3Sthurlow 10134bff34e3Sthurlow /* 10144bff34e3Sthurlow * Will we need an open handle for this setattr? 10154bff34e3Sthurlow * If so, what rights will we need? 10164bff34e3Sthurlow */ 10174bff34e3Sthurlow if (mask & (AT_ATIME | AT_MTIME)) { 10184bff34e3Sthurlow rights |= 10194bff34e3Sthurlow SA_RIGHT_FILE_WRITE_ATTRIBUTES | 10204bff34e3Sthurlow GENERIC_RIGHT_ALL_ACCESS | 10214bff34e3Sthurlow GENERIC_RIGHT_WRITE_ACCESS; 10224bff34e3Sthurlow } 10234bff34e3Sthurlow if (mask & AT_SIZE) { 10244bff34e3Sthurlow rights |= 10254bff34e3Sthurlow SA_RIGHT_FILE_WRITE_DATA | 10264bff34e3Sthurlow SA_RIGHT_FILE_APPEND_DATA; 10274bff34e3Sthurlow /* 10284bff34e3Sthurlow * Only SIZE requires a handle. 10294bff34e3Sthurlow * XXX May be more reliable to just 10304bff34e3Sthurlow * always get the file handle here. 1031613a2f6bSGordon Ross * The tmpopen checks n_vcgenid. 10324bff34e3Sthurlow */ 10334bff34e3Sthurlow error = smbfs_smb_tmpopen(np, rights, &scred, &fid); 10344bff34e3Sthurlow if (error) { 10354bff34e3Sthurlow SMBVDEBUG("error %d opening %s\n", 10364bff34e3Sthurlow error, np->n_rpath); 10374bff34e3Sthurlow goto out; 10384bff34e3Sthurlow } 10394bff34e3Sthurlow have_fid = 1; 10404bff34e3Sthurlow } 10414bff34e3Sthurlow 10424bff34e3Sthurlow 10434bff34e3Sthurlow /* 10444bff34e3Sthurlow * If the server supports the UNIX extensions, right here is where 10454bff34e3Sthurlow * we'd support changes to uid, gid, mode, and possibly va_flags. 10464bff34e3Sthurlow * For now we claim to have made any such changes. 10474bff34e3Sthurlow */ 10484bff34e3Sthurlow 10494bff34e3Sthurlow if (mask & AT_SIZE) { 10504bff34e3Sthurlow /* 10514bff34e3Sthurlow * If the new file size is less than what the client sees as 10524bff34e3Sthurlow * the file size, then just change the size and invalidate 10534bff34e3Sthurlow * the pages. 10544bff34e3Sthurlow * I am commenting this code at present because the function 10554bff34e3Sthurlow * smbfs_putapage() is not yet implemented. 10564bff34e3Sthurlow */ 10574bff34e3Sthurlow 10584bff34e3Sthurlow /* 10594bff34e3Sthurlow * Set the file size to vap->va_size. 10604bff34e3Sthurlow */ 10614bff34e3Sthurlow ASSERT(have_fid); 10624bff34e3Sthurlow error = smbfs_smb_setfsize(np, fid, vap->va_size, &scred); 10634bff34e3Sthurlow if (error) { 10644bff34e3Sthurlow SMBVDEBUG("setsize error %d file %s\n", 10654bff34e3Sthurlow error, np->n_rpath); 10664bff34e3Sthurlow } else { 10674bff34e3Sthurlow /* 10684bff34e3Sthurlow * Darwin had code here to zero-extend. 10694bff34e3Sthurlow * Tests indicate the server will zero-fill, 10704bff34e3Sthurlow * so looks like we don't need to do this. 10714bff34e3Sthurlow * Good thing, as this could take forever. 1072613a2f6bSGordon Ross * 1073613a2f6bSGordon Ross * XXX: Reportedly, writing one byte of zero 1074613a2f6bSGordon Ross * at the end offset avoids problems here. 10754bff34e3Sthurlow */ 10764bff34e3Sthurlow mutex_enter(&np->r_statelock); 10774bff34e3Sthurlow np->r_size = vap->va_size; 10784bff34e3Sthurlow mutex_exit(&np->r_statelock); 10794bff34e3Sthurlow modified = 1; 10804bff34e3Sthurlow } 10814bff34e3Sthurlow } 10824bff34e3Sthurlow 10834bff34e3Sthurlow /* 10844bff34e3Sthurlow * XXX: When Solaris has create_time, set that too. 10854bff34e3Sthurlow * Note: create_time is different from ctime. 10864bff34e3Sthurlow */ 10874bff34e3Sthurlow mtime = ((mask & AT_MTIME) ? &vap->va_mtime : 0); 10884bff34e3Sthurlow atime = ((mask & AT_ATIME) ? &vap->va_atime : 0); 10894bff34e3Sthurlow 10904bff34e3Sthurlow if (mtime || atime) { 10914bff34e3Sthurlow /* 10924bff34e3Sthurlow * If file is opened with write-attributes capability, 10934bff34e3Sthurlow * we use handle-based calls. If not, we use path-based ones. 10944bff34e3Sthurlow */ 10954bff34e3Sthurlow if (have_fid) { 10964bff34e3Sthurlow error = smbfs_smb_setfattr(np, fid, 10974bff34e3Sthurlow np->n_dosattr, mtime, atime, &scred); 10984bff34e3Sthurlow } else { 10994bff34e3Sthurlow error = smbfs_smb_setpattr(np, 11004bff34e3Sthurlow np->n_dosattr, mtime, atime, &scred); 11014bff34e3Sthurlow } 11024bff34e3Sthurlow if (error) { 11034bff34e3Sthurlow SMBVDEBUG("set times error %d file %s\n", 11044bff34e3Sthurlow error, np->n_rpath); 11054bff34e3Sthurlow } else { 11064bff34e3Sthurlow /* XXX: set np->n_mtime, etc? */ 11074bff34e3Sthurlow modified = 1; 11084bff34e3Sthurlow } 11094bff34e3Sthurlow } 11104bff34e3Sthurlow 11114bff34e3Sthurlow out: 11124bff34e3Sthurlow if (modified) { 11134bff34e3Sthurlow /* 11144bff34e3Sthurlow * Invalidate attribute cache in case if server doesn't set 11154bff34e3Sthurlow * required attributes. 11164bff34e3Sthurlow */ 11174bff34e3Sthurlow smbfs_attr_cacheremove(np); 11184bff34e3Sthurlow /* 11194bff34e3Sthurlow * XXX Darwin called _getattr here to 11204bff34e3Sthurlow * update the mtime. Should we? 11214bff34e3Sthurlow */ 11224bff34e3Sthurlow } 11234bff34e3Sthurlow 11244bff34e3Sthurlow if (have_fid) { 11254bff34e3Sthurlow cerror = smbfs_smb_tmpclose(np, fid, &scred); 11264bff34e3Sthurlow if (cerror) 11274bff34e3Sthurlow SMBERROR("error %d closing %s\n", 11284bff34e3Sthurlow cerror, np->n_rpath); 11294bff34e3Sthurlow } 11304bff34e3Sthurlow 11314bff34e3Sthurlow smb_credrele(&scred); 11324bff34e3Sthurlow smbfs_rw_exit(&np->r_lkserlock); 11334bff34e3Sthurlow 11344bff34e3Sthurlow return (error); 11354bff34e3Sthurlow } 11364bff34e3Sthurlow 11374bff34e3Sthurlow /* 11384bff34e3Sthurlow * smbfs_access_rwx() 11394bff34e3Sthurlow * Common function for smbfs_access, etc. 11404bff34e3Sthurlow * 11414bff34e3Sthurlow * The security model implemented by the FS is unusual 11424bff34e3Sthurlow * due to our "single user mounts" restriction. 11434bff34e3Sthurlow * 11444bff34e3Sthurlow * All access under a given mount point uses the CIFS 11454bff34e3Sthurlow * credentials established by the owner of the mount. 11464bff34e3Sthurlow * The Unix uid/gid/mode information is not (easily) 11474bff34e3Sthurlow * provided by CIFS, and is instead fabricated using 11484bff34e3Sthurlow * settings held in the mount structure. 11494bff34e3Sthurlow * 11504bff34e3Sthurlow * Most access checking is handled by the CIFS server, 11514bff34e3Sthurlow * but we need sufficient Unix access checks here to 11524bff34e3Sthurlow * prevent other local Unix users from having access 11534bff34e3Sthurlow * to objects under this mount that the uid/gid/mode 11544bff34e3Sthurlow * settings in the mount would not allow. 11554bff34e3Sthurlow * 11564bff34e3Sthurlow * With this model, there is a case where we need the 11574bff34e3Sthurlow * ability to do an access check before we have the 11584bff34e3Sthurlow * vnode for an object. This function takes advantage 11594bff34e3Sthurlow * of the fact that the uid/gid/mode is per mount, and 11604bff34e3Sthurlow * avoids the need for a vnode. 11614bff34e3Sthurlow * 11624bff34e3Sthurlow * We still (sort of) need a vnode when we call 11634bff34e3Sthurlow * secpolicy_vnode_access, but that only uses 11644bff34e3Sthurlow * the vtype field, so we can use a pair of fake 11654bff34e3Sthurlow * vnodes that have only v_type filled in. 11664bff34e3Sthurlow * 11674bff34e3Sthurlow * XXX: Later, add a new secpolicy_vtype_access() 11684bff34e3Sthurlow * that takes the vtype instead of a vnode, and 11694bff34e3Sthurlow * get rid of the tmpl_vxxx fake vnodes below. 11704bff34e3Sthurlow */ 11714bff34e3Sthurlow static int 11724bff34e3Sthurlow smbfs_access_rwx(vfs_t *vfsp, int vtype, int mode, cred_t *cr) 11734bff34e3Sthurlow { 11744bff34e3Sthurlow /* See the secpolicy call below. */ 11754bff34e3Sthurlow static const vnode_t tmpl_vdir = { .v_type = VDIR }; 11764bff34e3Sthurlow static const vnode_t tmpl_vreg = { .v_type = VREG }; 11774bff34e3Sthurlow vattr_t va; 11784bff34e3Sthurlow vnode_t *tvp; 11794bff34e3Sthurlow struct smbmntinfo *smi = VFTOSMI(vfsp); 11804bff34e3Sthurlow int shift = 0; 11814bff34e3Sthurlow 11824bff34e3Sthurlow /* 11834bff34e3Sthurlow * Build our (fabricated) vnode attributes. 11844bff34e3Sthurlow * XXX: Could make these templates in the 11854bff34e3Sthurlow * per-mount struct and use them here. 11864bff34e3Sthurlow */ 11874bff34e3Sthurlow bzero(&va, sizeof (va)); 11884bff34e3Sthurlow va.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID; 11894bff34e3Sthurlow va.va_type = vtype; 11904bff34e3Sthurlow va.va_mode = (vtype == VDIR) ? 11914bff34e3Sthurlow smi->smi_args.dir_mode : 11924bff34e3Sthurlow smi->smi_args.file_mode; 11934bff34e3Sthurlow va.va_uid = smi->smi_args.uid; 11944bff34e3Sthurlow va.va_gid = smi->smi_args.gid; 11954bff34e3Sthurlow 11964bff34e3Sthurlow /* 11974bff34e3Sthurlow * Disallow write attempts on read-only file systems, 11984bff34e3Sthurlow * unless the file is a device or fifo node. Note: 11994bff34e3Sthurlow * Inline vn_is_readonly and IS_DEVVP here because 12004bff34e3Sthurlow * we may not have a vnode ptr. Original expr. was: 12014bff34e3Sthurlow * (mode & VWRITE) && vn_is_readonly(vp) && !IS_DEVVP(vp)) 12024bff34e3Sthurlow */ 12034bff34e3Sthurlow if ((mode & VWRITE) && 12044bff34e3Sthurlow (vfsp->vfs_flag & VFS_RDONLY) && 12054bff34e3Sthurlow !(vtype == VCHR || vtype == VBLK || vtype == VFIFO)) 12064bff34e3Sthurlow return (EROFS); 12074bff34e3Sthurlow 12084bff34e3Sthurlow /* 12094bff34e3Sthurlow * Disallow attempts to access mandatory lock files. 12104bff34e3Sthurlow * Similarly, expand MANDLOCK here. 12114bff34e3Sthurlow * XXX: not sure we need this. 12124bff34e3Sthurlow */ 12134bff34e3Sthurlow if ((mode & (VWRITE | VREAD | VEXEC)) && 12144bff34e3Sthurlow va.va_type == VREG && MANDMODE(va.va_mode)) 12154bff34e3Sthurlow return (EACCES); 12164bff34e3Sthurlow 12174bff34e3Sthurlow /* 12184bff34e3Sthurlow * Access check is based on only 12194bff34e3Sthurlow * one of owner, group, public. 12204bff34e3Sthurlow * If not owner, then check group. 12214bff34e3Sthurlow * If not a member of the group, 12224bff34e3Sthurlow * then check public access. 12234bff34e3Sthurlow */ 12244bff34e3Sthurlow if (crgetuid(cr) != va.va_uid) { 12254bff34e3Sthurlow shift += 3; 12264bff34e3Sthurlow if (!groupmember(va.va_gid, cr)) 12274bff34e3Sthurlow shift += 3; 12284bff34e3Sthurlow } 12294bff34e3Sthurlow mode &= ~(va.va_mode << shift); 12304bff34e3Sthurlow if (mode == 0) 12314bff34e3Sthurlow return (0); 12324bff34e3Sthurlow 12334bff34e3Sthurlow /* 12344bff34e3Sthurlow * We need a vnode for secpolicy_vnode_access, 12354bff34e3Sthurlow * but the only thing it looks at is v_type, 12364bff34e3Sthurlow * so pass one of the templates above. 12374bff34e3Sthurlow */ 12384bff34e3Sthurlow tvp = (va.va_type == VDIR) ? 12394bff34e3Sthurlow (vnode_t *)&tmpl_vdir : 12404bff34e3Sthurlow (vnode_t *)&tmpl_vreg; 12414bff34e3Sthurlow return (secpolicy_vnode_access(cr, tvp, va.va_uid, mode)); 12424bff34e3Sthurlow } 12434bff34e3Sthurlow 12444bff34e3Sthurlow /* 12454bff34e3Sthurlow * See smbfs_setattr 12464bff34e3Sthurlow */ 12474bff34e3Sthurlow static int 12484bff34e3Sthurlow smbfs_accessx(void *arg, int mode, cred_t *cr) 12494bff34e3Sthurlow { 12504bff34e3Sthurlow vnode_t *vp = arg; 12514bff34e3Sthurlow /* 12524bff34e3Sthurlow * Note: The caller has checked the current zone, 12534bff34e3Sthurlow * the SMI_DEAD and VFS_UNMOUNTED flags, etc. 12544bff34e3Sthurlow */ 12554bff34e3Sthurlow return (smbfs_access_rwx(vp->v_vfsp, vp->v_type, mode, cr)); 12564bff34e3Sthurlow } 12574bff34e3Sthurlow 12584bff34e3Sthurlow /* 12594bff34e3Sthurlow * XXX 12604bff34e3Sthurlow * This op should support PSARC 2007/403, Modified Access Checks for CIFS 12614bff34e3Sthurlow */ 12624bff34e3Sthurlow /* ARGSUSED */ 12634bff34e3Sthurlow static int 12644bff34e3Sthurlow smbfs_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct) 12654bff34e3Sthurlow { 12664bff34e3Sthurlow vfs_t *vfsp; 12674bff34e3Sthurlow smbmntinfo_t *smi; 12684bff34e3Sthurlow 12694bff34e3Sthurlow vfsp = vp->v_vfsp; 12704bff34e3Sthurlow smi = VFTOSMI(vfsp); 12714bff34e3Sthurlow 12724bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 12734bff34e3Sthurlow return (EIO); 12744bff34e3Sthurlow 12754bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 12764bff34e3Sthurlow return (EIO); 12774bff34e3Sthurlow 12784bff34e3Sthurlow return (smbfs_access_rwx(vfsp, vp->v_type, mode, cr)); 12794bff34e3Sthurlow } 12804bff34e3Sthurlow 12814bff34e3Sthurlow 12824bff34e3Sthurlow /* 12834bff34e3Sthurlow * Flush local dirty pages to stable storage on the server. 12844bff34e3Sthurlow * 12854bff34e3Sthurlow * If FNODSYNC is specified, then there is nothing to do because 12864bff34e3Sthurlow * metadata changes are not cached on the client before being 12874bff34e3Sthurlow * sent to the server. 12884bff34e3Sthurlow */ 12894bff34e3Sthurlow /* ARGSUSED */ 12904bff34e3Sthurlow static int 12914bff34e3Sthurlow smbfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct) 12924bff34e3Sthurlow { 12934bff34e3Sthurlow int error = 0; 12944bff34e3Sthurlow smbmntinfo_t *smi; 12952f5e3e91SGordon Ross smbnode_t *np; 12962f5e3e91SGordon Ross struct smb_cred scred; 12974bff34e3Sthurlow 12982f5e3e91SGordon Ross np = VTOSMB(vp); 12994bff34e3Sthurlow smi = VTOSMI(vp); 13004bff34e3Sthurlow 13014bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 13024bff34e3Sthurlow return (EIO); 13034bff34e3Sthurlow 13044bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 13054bff34e3Sthurlow return (EIO); 13064bff34e3Sthurlow 13074bff34e3Sthurlow if ((syncflag & FNODSYNC) || IS_SWAPVP(vp)) 13084bff34e3Sthurlow return (0); 13094bff34e3Sthurlow 13102f5e3e91SGordon Ross if ((syncflag & (FSYNC|FDSYNC)) == 0) 13112f5e3e91SGordon Ross return (0); 13122f5e3e91SGordon Ross 13132f5e3e91SGordon Ross /* Shared lock for n_fid use in _flush */ 13142f5e3e91SGordon Ross if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) 13152f5e3e91SGordon Ross return (EINTR); 1316613a2f6bSGordon Ross smb_credinit(&scred, cr); 13172f5e3e91SGordon Ross 13182f5e3e91SGordon Ross error = smbfs_smb_flush(np, &scred); 13192f5e3e91SGordon Ross 13202f5e3e91SGordon Ross smb_credrele(&scred); 13212f5e3e91SGordon Ross smbfs_rw_exit(&np->r_lkserlock); 13222f5e3e91SGordon Ross 13234bff34e3Sthurlow return (error); 13244bff34e3Sthurlow } 13254bff34e3Sthurlow 13264bff34e3Sthurlow /* 13274bff34e3Sthurlow * Last reference to vnode went away. 13284bff34e3Sthurlow */ 13294bff34e3Sthurlow /* ARGSUSED */ 13304bff34e3Sthurlow static void 13314bff34e3Sthurlow smbfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct) 13324bff34e3Sthurlow { 13334bff34e3Sthurlow smbnode_t *np; 13344bff34e3Sthurlow 13354bff34e3Sthurlow /* 13364bff34e3Sthurlow * Don't "bail out" for VFS_UNMOUNTED here, 13374bff34e3Sthurlow * as we want to do cleanup, etc. 13384bff34e3Sthurlow * See also pcfs_inactive 13394bff34e3Sthurlow */ 13404bff34e3Sthurlow 13414bff34e3Sthurlow np = VTOSMB(vp); 13424bff34e3Sthurlow 13434bff34e3Sthurlow /* 13444bff34e3Sthurlow * If this is coming from the wrong zone, we let someone in the right 13454bff34e3Sthurlow * zone take care of it asynchronously. We can get here due to 13464bff34e3Sthurlow * VN_RELE() being called from pageout() or fsflush(). This call may 13474bff34e3Sthurlow * potentially turn into an expensive no-op if, for instance, v_count 13484bff34e3Sthurlow * gets incremented in the meantime, but it's still correct. 13494bff34e3Sthurlow */ 13504bff34e3Sthurlow 13514bff34e3Sthurlow /* 13524bff34e3Sthurlow * Some paranoia from the Darwin code: 13534bff34e3Sthurlow * Make sure the FID was closed. 13544bff34e3Sthurlow * If we see this, it's a bug! 13554bff34e3Sthurlow * 13564bff34e3Sthurlow * No rw_enter here, as this should be the 13574bff34e3Sthurlow * last ref, and we're just looking... 13584bff34e3Sthurlow */ 13594bff34e3Sthurlow if (np->n_fidrefs > 0) { 13604bff34e3Sthurlow SMBVDEBUG("opencount %d fid %d file %s\n", 13614bff34e3Sthurlow np->n_fidrefs, np->n_fid, np->n_rpath); 13624bff34e3Sthurlow } 13634bff34e3Sthurlow if (np->n_dirrefs > 0) { 13644bff34e3Sthurlow uint_t fid = (np->n_dirseq) ? 13654bff34e3Sthurlow np->n_dirseq->f_Sid : 0; 13664bff34e3Sthurlow SMBVDEBUG("opencount %d fid %d dir %s\n", 13674bff34e3Sthurlow np->n_dirrefs, fid, np->n_rpath); 13684bff34e3Sthurlow } 13694bff34e3Sthurlow 13704bff34e3Sthurlow smb_addfree(np); 13714bff34e3Sthurlow } 13724bff34e3Sthurlow 13734bff34e3Sthurlow /* 13744bff34e3Sthurlow * Remote file system operations having to do with directory manipulation. 13754bff34e3Sthurlow */ 13764bff34e3Sthurlow /* ARGSUSED */ 13774bff34e3Sthurlow static int 13784bff34e3Sthurlow smbfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp, 13794bff34e3Sthurlow int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct, 13804bff34e3Sthurlow int *direntflags, pathname_t *realpnp) 13814bff34e3Sthurlow { 138291d632c8Sgwr vfs_t *vfs; 13834bff34e3Sthurlow smbmntinfo_t *smi; 138491d632c8Sgwr smbnode_t *dnp; 138591d632c8Sgwr int error; 13864bff34e3Sthurlow 138791d632c8Sgwr vfs = dvp->v_vfsp; 138891d632c8Sgwr smi = VFTOSMI(vfs); 13894bff34e3Sthurlow 13904bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 13914bff34e3Sthurlow return (EPERM); 13924bff34e3Sthurlow 139391d632c8Sgwr if (smi->smi_flags & SMI_DEAD || vfs->vfs_flag & VFS_UNMOUNTED) 13944bff34e3Sthurlow return (EIO); 13954bff34e3Sthurlow 13964bff34e3Sthurlow dnp = VTOSMB(dvp); 139791d632c8Sgwr 139891d632c8Sgwr /* 139991d632c8Sgwr * Are we looking up extended attributes? If so, "dvp" is 140091d632c8Sgwr * the file or directory for which we want attributes, and 140191d632c8Sgwr * we need a lookup of the (faked up) attribute directory 140291d632c8Sgwr * before we lookup the rest of the path. 140391d632c8Sgwr */ 140491d632c8Sgwr if (flags & LOOKUP_XATTR) { 140591d632c8Sgwr /* 140691d632c8Sgwr * Require the xattr mount option. 140791d632c8Sgwr */ 140891d632c8Sgwr if ((vfs->vfs_flag & VFS_XATTR) == 0) 140991d632c8Sgwr return (EINVAL); 141091d632c8Sgwr 141191d632c8Sgwr /* 141291d632c8Sgwr * We don't allow recursive attributes. 141391d632c8Sgwr */ 141491d632c8Sgwr if (dnp->n_flag & N_XATTR) 141591d632c8Sgwr return (EINVAL); 141691d632c8Sgwr 141791d632c8Sgwr error = smbfs_get_xattrdir(dvp, vpp, cr, flags); 141891d632c8Sgwr return (error); 141991d632c8Sgwr } 142091d632c8Sgwr 14214bff34e3Sthurlow if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_READER, SMBINTR(dvp))) { 14224bff34e3Sthurlow error = EINTR; 14234bff34e3Sthurlow goto out; 14244bff34e3Sthurlow } 14254bff34e3Sthurlow 14264bff34e3Sthurlow error = smbfslookup(dvp, nm, vpp, cr, 1, ct); 14274bff34e3Sthurlow 14284bff34e3Sthurlow smbfs_rw_exit(&dnp->r_rwlock); 14294bff34e3Sthurlow 14304bff34e3Sthurlow out: 14314bff34e3Sthurlow return (error); 14324bff34e3Sthurlow } 14334bff34e3Sthurlow 14344bff34e3Sthurlow /* ARGSUSED */ 14354bff34e3Sthurlow static int 14364bff34e3Sthurlow smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, int dnlc, 14374bff34e3Sthurlow caller_context_t *ct) 14384bff34e3Sthurlow { 14394bff34e3Sthurlow int error; 14404bff34e3Sthurlow int supplen; /* supported length */ 14414bff34e3Sthurlow vnode_t *vp; 14424bff34e3Sthurlow smbnode_t *dnp; 14434bff34e3Sthurlow smbmntinfo_t *smi; 14444bff34e3Sthurlow /* struct smb_vc *vcp; */ 144591d632c8Sgwr const char *ill; 14464bff34e3Sthurlow const char *name = (const char *)nm; 14474bff34e3Sthurlow int nmlen = strlen(nm); 14484bff34e3Sthurlow int rplen; 14494bff34e3Sthurlow struct smb_cred scred; 14504bff34e3Sthurlow struct smbfattr fa; 14514bff34e3Sthurlow 14524bff34e3Sthurlow smi = VTOSMI(dvp); 14534bff34e3Sthurlow dnp = VTOSMB(dvp); 14544bff34e3Sthurlow 14554bff34e3Sthurlow ASSERT(curproc->p_zone == smi->smi_zone); 14564bff34e3Sthurlow 14574bff34e3Sthurlow #ifdef NOT_YET 14584bff34e3Sthurlow vcp = SSTOVC(smi->smi_share); 14594bff34e3Sthurlow 14604bff34e3Sthurlow /* XXX: Should compute this once and store it in smbmntinfo_t */ 14614bff34e3Sthurlow supplen = (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) ? 255 : 12; 14624bff34e3Sthurlow #else 14634bff34e3Sthurlow supplen = 255; 14644bff34e3Sthurlow #endif 14654bff34e3Sthurlow 14664bff34e3Sthurlow /* 14674bff34e3Sthurlow * RWlock must be held, either reader or writer. 14684bff34e3Sthurlow * XXX: Can we check without looking directly 14694bff34e3Sthurlow * inside the struct smbfs_rwlock_t? 14704bff34e3Sthurlow */ 14714bff34e3Sthurlow ASSERT(dnp->r_rwlock.count != 0); 14724bff34e3Sthurlow 14734bff34e3Sthurlow /* 14744bff34e3Sthurlow * If lookup is for "", just return dvp. Don't need 14754bff34e3Sthurlow * to send it over the wire, look it up in the dnlc, 14764bff34e3Sthurlow * or perform any access checks. 14774bff34e3Sthurlow */ 14784bff34e3Sthurlow if (nmlen == 0) { 14794bff34e3Sthurlow VN_HOLD(dvp); 14804bff34e3Sthurlow *vpp = dvp; 14814bff34e3Sthurlow return (0); 14824bff34e3Sthurlow } 14834bff34e3Sthurlow 14844bff34e3Sthurlow /* 148591d632c8Sgwr * Can't do lookups in non-directories. 14864bff34e3Sthurlow */ 14874bff34e3Sthurlow if (dvp->v_type != VDIR) 14884bff34e3Sthurlow return (ENOTDIR); 14894bff34e3Sthurlow 149091d632c8Sgwr /* 149191d632c8Sgwr * Need search permission in the directory. 149291d632c8Sgwr */ 14934bff34e3Sthurlow error = smbfs_access(dvp, VEXEC, 0, cr, ct); 14944bff34e3Sthurlow if (error) 14954bff34e3Sthurlow return (error); 14964bff34e3Sthurlow 14974bff34e3Sthurlow /* 14984bff34e3Sthurlow * If lookup is for ".", just return dvp. Don't need 14994bff34e3Sthurlow * to send it over the wire or look it up in the dnlc, 15004bff34e3Sthurlow * just need to check access (done above). 15014bff34e3Sthurlow */ 15024bff34e3Sthurlow if (nmlen == 1 && name[0] == '.') { 15034bff34e3Sthurlow VN_HOLD(dvp); 15044bff34e3Sthurlow *vpp = dvp; 15054bff34e3Sthurlow return (0); 15064bff34e3Sthurlow } 15074bff34e3Sthurlow 15084bff34e3Sthurlow /* 150991d632c8Sgwr * Now some sanity checks on the name. 151091d632c8Sgwr * First check the length. 15114bff34e3Sthurlow */ 151291d632c8Sgwr if (nmlen > supplen) 151391d632c8Sgwr return (ENAMETOOLONG); 151491d632c8Sgwr 151591d632c8Sgwr /* 151691d632c8Sgwr * Avoid surprises with characters that are 151791d632c8Sgwr * illegal in Windows file names. 151891d632c8Sgwr * Todo: CATIA mappings XXX 151991d632c8Sgwr */ 152091d632c8Sgwr ill = illegal_chars; 152191d632c8Sgwr if (dnp->n_flag & N_XATTR) 152291d632c8Sgwr ill++; /* allow colon */ 152391d632c8Sgwr if (strpbrk(nm, ill)) 152491d632c8Sgwr return (EINVAL); 152591d632c8Sgwr 152691d632c8Sgwr #ifdef USE_DNLC 152791d632c8Sgwr if (dnlc) { 152891d632c8Sgwr /* 152991d632c8Sgwr * Lookup this name in the DNLC. If there was a valid entry, 153091d632c8Sgwr * then return the results of the lookup. 153191d632c8Sgwr */ 153291d632c8Sgwr error = smbfslookup_dnlc(dvp, nm, vpp, cr); 153391d632c8Sgwr if (error || *vpp != NULL) 153491d632c8Sgwr return (error); 15354bff34e3Sthurlow } 153691d632c8Sgwr #endif /* USE_DNLC */ 15374bff34e3Sthurlow 15384bff34e3Sthurlow /* 15394bff34e3Sthurlow * Handle lookup of ".." which is quite tricky, 15404bff34e3Sthurlow * because the protocol gives us little help. 15414bff34e3Sthurlow * 15424bff34e3Sthurlow * We keep full pathnames (as seen on the server) 15434bff34e3Sthurlow * so we can just trim off the last component to 15444bff34e3Sthurlow * get the full pathname of the parent. Note: 15454bff34e3Sthurlow * We don't actually copy and modify, but just 15464bff34e3Sthurlow * compute the trimmed length and pass that with 15474bff34e3Sthurlow * the current dir path (not null terminated). 15484bff34e3Sthurlow * 15494bff34e3Sthurlow * We don't go over-the-wire to get attributes 15504bff34e3Sthurlow * for ".." because we know it's a directory, 15514bff34e3Sthurlow * and we can just leave the rest "stale" 15524bff34e3Sthurlow * until someone does a getattr. 15534bff34e3Sthurlow */ 15544bff34e3Sthurlow if (nmlen == 2 && name[0] == '.' && name[1] == '.') { 15554bff34e3Sthurlow if (dvp->v_flag & VROOT) { 15564bff34e3Sthurlow /* 15574bff34e3Sthurlow * Already at the root. This can happen 15584bff34e3Sthurlow * with directory listings at the root, 15594bff34e3Sthurlow * which lookup "." and ".." to get the 15604bff34e3Sthurlow * inode numbers. Let ".." be the same 15614bff34e3Sthurlow * as "." in the FS root. 15624bff34e3Sthurlow */ 15634bff34e3Sthurlow VN_HOLD(dvp); 15644bff34e3Sthurlow *vpp = dvp; 15654bff34e3Sthurlow return (0); 15664bff34e3Sthurlow } 15674bff34e3Sthurlow 156891d632c8Sgwr /* 156991d632c8Sgwr * Special case for XATTR directory 157091d632c8Sgwr */ 157191d632c8Sgwr if (dvp->v_flag & V_XATTRDIR) { 157291d632c8Sgwr error = smbfs_xa_parent(dvp, vpp); 157391d632c8Sgwr /* Intentionally no dnlc_update */ 157491d632c8Sgwr return (error); 157591d632c8Sgwr } 157691d632c8Sgwr 15774bff34e3Sthurlow /* 15784bff34e3Sthurlow * Find the parent path length. 15794bff34e3Sthurlow */ 15804bff34e3Sthurlow rplen = dnp->n_rplen; 15814bff34e3Sthurlow ASSERT(rplen > 0); 15824bff34e3Sthurlow while (--rplen >= 0) { 15834bff34e3Sthurlow if (dnp->n_rpath[rplen] == '\\') 15844bff34e3Sthurlow break; 15854bff34e3Sthurlow } 15864bff34e3Sthurlow if (rplen == 0) { 15874bff34e3Sthurlow /* Found our way to the root. */ 15884bff34e3Sthurlow vp = SMBTOV(smi->smi_root); 15894bff34e3Sthurlow VN_HOLD(vp); 15904bff34e3Sthurlow *vpp = vp; 15914bff34e3Sthurlow return (0); 15924bff34e3Sthurlow } 15934bff34e3Sthurlow vp = smbfs_make_node(dvp->v_vfsp, 15944bff34e3Sthurlow dnp->n_rpath, rplen, 159591d632c8Sgwr NULL, 0, 0, NULL); 159691d632c8Sgwr ASSERT(vp); 15974bff34e3Sthurlow vp->v_type = VDIR; 159891d632c8Sgwr #ifdef USE_DNLC 159991d632c8Sgwr dnlc_update(dvp, nm, vp); 160091d632c8Sgwr #endif 16014bff34e3Sthurlow 16024bff34e3Sthurlow /* Success! */ 16034bff34e3Sthurlow *vpp = vp; 16044bff34e3Sthurlow return (0); 16054bff34e3Sthurlow } 16064bff34e3Sthurlow 16074bff34e3Sthurlow /* 16084bff34e3Sthurlow * Normal lookup of a child node. 16094bff34e3Sthurlow * Note we handled "." and ".." above. 16104bff34e3Sthurlow * 16114bff34e3Sthurlow * First, go over-the-wire to get the 16124bff34e3Sthurlow * node type (and attributes). 16134bff34e3Sthurlow */ 1614613a2f6bSGordon Ross smb_credinit(&scred, cr); 16154bff34e3Sthurlow /* Note: this can allocate a new "name" */ 16164bff34e3Sthurlow error = smbfs_smb_lookup(dnp, &name, &nmlen, &fa, &scred); 16174bff34e3Sthurlow smb_credrele(&scred); 161891d632c8Sgwr #ifdef USE_DNLC 161991d632c8Sgwr if (error == ENOENT) 162091d632c8Sgwr dnlc_enter(dvp, nm, DNLC_NO_VNODE); 162191d632c8Sgwr #endif 16224bff34e3Sthurlow if (error) 16234bff34e3Sthurlow goto out; 16244bff34e3Sthurlow 16254bff34e3Sthurlow /* 16264bff34e3Sthurlow * Find or create the node. 16274bff34e3Sthurlow */ 16284bff34e3Sthurlow error = smbfs_nget(dvp, name, nmlen, &fa, &vp); 16294bff34e3Sthurlow if (error) 16304bff34e3Sthurlow goto out; 16314bff34e3Sthurlow 163291d632c8Sgwr #ifdef USE_DNLC 163391d632c8Sgwr dnlc_update(dvp, nm, vp); 163491d632c8Sgwr #endif 163591d632c8Sgwr 16364bff34e3Sthurlow /* Success! */ 16374bff34e3Sthurlow *vpp = vp; 16384bff34e3Sthurlow 16394bff34e3Sthurlow out: 16404bff34e3Sthurlow /* smbfs_smb_lookup may have allocated name. */ 16414bff34e3Sthurlow if (name != nm) 16424bff34e3Sthurlow smbfs_name_free(name, nmlen); 16434bff34e3Sthurlow 16444bff34e3Sthurlow return (error); 16454bff34e3Sthurlow } 16464bff34e3Sthurlow 164791d632c8Sgwr #ifdef USE_DNLC 164891d632c8Sgwr #ifdef DEBUG 164991d632c8Sgwr static int smbfs_lookup_dnlc_hits = 0; 165091d632c8Sgwr static int smbfs_lookup_dnlc_misses = 0; 165191d632c8Sgwr static int smbfs_lookup_dnlc_neg_hits = 0; 165291d632c8Sgwr static int smbfs_lookup_dnlc_disappears = 0; 165391d632c8Sgwr static int smbfs_lookup_dnlc_lookups = 0; 165491d632c8Sgwr #endif 165591d632c8Sgwr 165691d632c8Sgwr /* ARGSUSED */ 165791d632c8Sgwr static int 165891d632c8Sgwr smbfslookup_dnlc(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr) 165991d632c8Sgwr { 166091d632c8Sgwr int error; 166191d632c8Sgwr vnode_t *vp; 166291d632c8Sgwr struct vattr va; 166391d632c8Sgwr smbnode_t *dnp; 166491d632c8Sgwr 166591d632c8Sgwr dnp = VTOSMB(dvp); 166691d632c8Sgwr 166791d632c8Sgwr ASSERT(*nm != '\0'); 166891d632c8Sgwr ASSERT(curproc->p_zone == VTOSMI(dvp)->smi_zone); 166991d632c8Sgwr 167091d632c8Sgwr /* 167191d632c8Sgwr * Lookup this name in the DNLC. If successful, then validate 167291d632c8Sgwr * the caches and then recheck the DNLC. The DNLC is rechecked 167391d632c8Sgwr * just in case this entry got invalidated during the call 167491d632c8Sgwr * to smbfsgetattr(). 167591d632c8Sgwr * An assumption is being made that it is safe to say that a 167691d632c8Sgwr * file exists which may not on the server. Any operations to 167791d632c8Sgwr * the server will fail with ESTALE. 167891d632c8Sgwr */ 167991d632c8Sgwr 168091d632c8Sgwr #ifdef DEBUG 168191d632c8Sgwr smbfs_lookup_dnlc_lookups++; 168291d632c8Sgwr #endif 168391d632c8Sgwr vp = dnlc_lookup(dvp, nm); 168491d632c8Sgwr if (vp != NULL) { 168591d632c8Sgwr if (vp == DNLC_NO_VNODE && !vn_is_readonly(dvp)) 168691d632c8Sgwr smbfs_attr_cacheremove(dnp); 168791d632c8Sgwr VN_RELE(vp); 168891d632c8Sgwr error = smbfsgetattr(dvp, &va, cr); 168991d632c8Sgwr if (error) 169091d632c8Sgwr return (error); 169191d632c8Sgwr vp = dnlc_lookup(dvp, nm); 169291d632c8Sgwr if (vp != NULL) { 169391d632c8Sgwr /* 169491d632c8Sgwr * NFS checks VEXEC access here, 169591d632c8Sgwr * but we've already done that 169691d632c8Sgwr * in the caller. 169791d632c8Sgwr */ 169891d632c8Sgwr if (vp == DNLC_NO_VNODE) { 169991d632c8Sgwr VN_RELE(vp); 170091d632c8Sgwr #ifdef DEBUG 170191d632c8Sgwr smbfs_lookup_dnlc_neg_hits++; 170291d632c8Sgwr #endif 170391d632c8Sgwr return (ENOENT); 170491d632c8Sgwr } 170591d632c8Sgwr *vpp = vp; 170691d632c8Sgwr #ifdef DEBUG 170791d632c8Sgwr smbfs_lookup_dnlc_hits++; 170891d632c8Sgwr #endif 170991d632c8Sgwr return (0); 171091d632c8Sgwr } 171191d632c8Sgwr #ifdef DEBUG 171291d632c8Sgwr smbfs_lookup_dnlc_disappears++; 171391d632c8Sgwr #endif 171491d632c8Sgwr } 171591d632c8Sgwr #ifdef DEBUG 171691d632c8Sgwr else 171791d632c8Sgwr smbfs_lookup_dnlc_misses++; 171891d632c8Sgwr #endif 171991d632c8Sgwr *vpp = NULL; 172091d632c8Sgwr 172191d632c8Sgwr return (0); 172291d632c8Sgwr } 172391d632c8Sgwr #endif /* USE_DNLC */ 172491d632c8Sgwr 17254bff34e3Sthurlow /* 17264bff34e3Sthurlow * XXX 17274bff34e3Sthurlow * vsecattr_t is new to build 77, and we need to eventually support 17284bff34e3Sthurlow * it in order to create an ACL when an object is created. 17294bff34e3Sthurlow * 17304bff34e3Sthurlow * This op should support the new FIGNORECASE flag for case-insensitive 17314bff34e3Sthurlow * lookups, per PSARC 2007/244. 17324bff34e3Sthurlow */ 17334bff34e3Sthurlow /* ARGSUSED */ 17344bff34e3Sthurlow static int 17354bff34e3Sthurlow smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive, 17364bff34e3Sthurlow int mode, vnode_t **vpp, cred_t *cr, int lfaware, caller_context_t *ct, 17374bff34e3Sthurlow vsecattr_t *vsecp) 17384bff34e3Sthurlow { 17394bff34e3Sthurlow int error; 17404bff34e3Sthurlow int cerror; 17414bff34e3Sthurlow vfs_t *vfsp; 17424bff34e3Sthurlow vnode_t *vp; 17434bff34e3Sthurlow #ifdef NOT_YET 17444bff34e3Sthurlow smbnode_t *np; 17454bff34e3Sthurlow #endif 17464bff34e3Sthurlow smbnode_t *dnp; 17474bff34e3Sthurlow smbmntinfo_t *smi; 17484bff34e3Sthurlow struct vattr vattr; 17494bff34e3Sthurlow struct smbfattr fattr; 17504bff34e3Sthurlow struct smb_cred scred; 17514bff34e3Sthurlow const char *name = (const char *)nm; 17524bff34e3Sthurlow int nmlen = strlen(nm); 17534bff34e3Sthurlow uint32_t disp; 17544bff34e3Sthurlow uint16_t fid; 175591d632c8Sgwr int xattr; 17564bff34e3Sthurlow 17574bff34e3Sthurlow vfsp = dvp->v_vfsp; 17584bff34e3Sthurlow smi = VFTOSMI(vfsp); 17594bff34e3Sthurlow dnp = VTOSMB(dvp); 17604bff34e3Sthurlow vp = NULL; 17614bff34e3Sthurlow 17624bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 17634bff34e3Sthurlow return (EPERM); 17644bff34e3Sthurlow 17654bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 17664bff34e3Sthurlow return (EIO); 17674bff34e3Sthurlow 17684bff34e3Sthurlow /* 17694bff34e3Sthurlow * Note: this may break mknod(2) calls to create a directory, 17704bff34e3Sthurlow * but that's obscure use. Some other filesystems do this. 17714bff34e3Sthurlow * XXX: Later, redirect VDIR type here to _mkdir. 17724bff34e3Sthurlow */ 17734bff34e3Sthurlow if (va->va_type != VREG) 17744bff34e3Sthurlow return (EINVAL); 17754bff34e3Sthurlow 17764bff34e3Sthurlow /* 17774bff34e3Sthurlow * If the pathname is "", just use dvp, no checks. 17784bff34e3Sthurlow * Do this outside of the rwlock (like zfs). 17794bff34e3Sthurlow */ 17804bff34e3Sthurlow if (nmlen == 0) { 17814bff34e3Sthurlow VN_HOLD(dvp); 17824bff34e3Sthurlow *vpp = dvp; 17834bff34e3Sthurlow return (0); 17844bff34e3Sthurlow } 17854bff34e3Sthurlow 17864bff34e3Sthurlow /* Don't allow "." or ".." through here. */ 17874bff34e3Sthurlow if ((nmlen == 1 && name[0] == '.') || 17884bff34e3Sthurlow (nmlen == 2 && name[0] == '.' && name[1] == '.')) 17894bff34e3Sthurlow return (EISDIR); 17904bff34e3Sthurlow 17914bff34e3Sthurlow /* 17924bff34e3Sthurlow * We make a copy of the attributes because the caller does not 17934bff34e3Sthurlow * expect us to change what va points to. 17944bff34e3Sthurlow */ 17954bff34e3Sthurlow vattr = *va; 17964bff34e3Sthurlow 17974bff34e3Sthurlow if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp))) 17984bff34e3Sthurlow return (EINTR); 1799613a2f6bSGordon Ross smb_credinit(&scred, cr); 18004bff34e3Sthurlow 18014bff34e3Sthurlow /* 18024bff34e3Sthurlow * XXX: Do we need r_lkserlock too? 18034bff34e3Sthurlow * No use of any shared fid or fctx... 18044bff34e3Sthurlow */ 18054bff34e3Sthurlow 18064bff34e3Sthurlow /* 18074bff34e3Sthurlow * NFS needs to go over the wire, just to be sure whether the 18084bff34e3Sthurlow * file exists or not. Using the DNLC can be dangerous in 18094bff34e3Sthurlow * this case when making a decision regarding existence. 18104bff34e3Sthurlow * 18114bff34e3Sthurlow * The SMB protocol does NOT really need to go OTW here 18124bff34e3Sthurlow * thanks to the expressive NTCREATE disposition values. 18134bff34e3Sthurlow * Unfortunately, to do Unix access checks correctly, 18144bff34e3Sthurlow * we need to know if the object already exists. 18154bff34e3Sthurlow * When the object does not exist, we need VWRITE on 18164bff34e3Sthurlow * the directory. Note: smbfslookup() checks VEXEC. 18174bff34e3Sthurlow */ 18184bff34e3Sthurlow error = smbfslookup(dvp, nm, &vp, cr, 0, ct); 18194bff34e3Sthurlow if (error == 0) { 18204bff34e3Sthurlow /* 182142645588SGordon Ross * The file already exists. Error? 182242645588SGordon Ross * NB: have a hold from smbfslookup 18234bff34e3Sthurlow */ 18244bff34e3Sthurlow if (exclusive == EXCL) { 18254bff34e3Sthurlow error = EEXIST; 182642645588SGordon Ross VN_RELE(vp); 18274bff34e3Sthurlow goto out; 18284bff34e3Sthurlow } 18294bff34e3Sthurlow /* 18304bff34e3Sthurlow * Verify requested access. 18314bff34e3Sthurlow */ 18324bff34e3Sthurlow error = smbfs_access(vp, mode, 0, cr, ct); 183342645588SGordon Ross if (error) { 183442645588SGordon Ross VN_RELE(vp); 18354bff34e3Sthurlow goto out; 183642645588SGordon Ross } 18374bff34e3Sthurlow 18384bff34e3Sthurlow /* 18394bff34e3Sthurlow * Truncate (if requested). 18404bff34e3Sthurlow */ 18414bff34e3Sthurlow if ((vattr.va_mask & AT_SIZE) && vattr.va_size == 0) { 18424bff34e3Sthurlow vattr.va_mask = AT_SIZE; 18434bff34e3Sthurlow error = smbfssetattr(vp, &vattr, 0, cr); 184442645588SGordon Ross if (error) { 184542645588SGordon Ross VN_RELE(vp); 18464bff34e3Sthurlow goto out; 184742645588SGordon Ross } 18484bff34e3Sthurlow } 18494bff34e3Sthurlow /* Success! */ 18504bff34e3Sthurlow #ifdef NOT_YET 18514bff34e3Sthurlow vnevent_create(vp, ct); 18524bff34e3Sthurlow #endif 18534bff34e3Sthurlow *vpp = vp; 18544bff34e3Sthurlow goto out; 18554bff34e3Sthurlow } 18564bff34e3Sthurlow 18574bff34e3Sthurlow /* 18584bff34e3Sthurlow * The file did not exist. Need VWRITE in the directory. 18594bff34e3Sthurlow */ 18604bff34e3Sthurlow error = smbfs_access(dvp, VWRITE, 0, cr, ct); 18614bff34e3Sthurlow if (error) 18624bff34e3Sthurlow goto out; 18634bff34e3Sthurlow 18644bff34e3Sthurlow /* 18654bff34e3Sthurlow * Now things get tricky. We also need to check the 18664bff34e3Sthurlow * requested open mode against the file we may create. 18674bff34e3Sthurlow * See comments at smbfs_access_rwx 18684bff34e3Sthurlow */ 18694bff34e3Sthurlow error = smbfs_access_rwx(vfsp, VREG, mode, cr); 18704bff34e3Sthurlow if (error) 18714bff34e3Sthurlow goto out; 18724bff34e3Sthurlow 187391d632c8Sgwr /* remove possible negative entry from the dnlc */ 187491d632c8Sgwr dnlc_remove(dvp, nm); 18754bff34e3Sthurlow 18764bff34e3Sthurlow /* 18774bff34e3Sthurlow * Now the code derived from Darwin, 18784bff34e3Sthurlow * but with greater use of NT_CREATE 18794bff34e3Sthurlow * disposition options. Much changed. 18804bff34e3Sthurlow * 18814bff34e3Sthurlow * Create (or open) a new child node. 18824bff34e3Sthurlow * Note we handled "." and ".." above. 18834bff34e3Sthurlow */ 18844bff34e3Sthurlow 18854bff34e3Sthurlow if (exclusive == EXCL) 18864bff34e3Sthurlow disp = NTCREATEX_DISP_CREATE; 18874bff34e3Sthurlow else { 18884bff34e3Sthurlow /* Truncate regular files if requested. */ 18894bff34e3Sthurlow if ((va->va_type == VREG) && 18904bff34e3Sthurlow (va->va_mask & AT_SIZE) && 18914bff34e3Sthurlow (va->va_size == 0)) 18924bff34e3Sthurlow disp = NTCREATEX_DISP_OVERWRITE_IF; 18934bff34e3Sthurlow else 18944bff34e3Sthurlow disp = NTCREATEX_DISP_OPEN_IF; 18954bff34e3Sthurlow } 189691d632c8Sgwr xattr = (dnp->n_flag & N_XATTR) ? 1 : 0; 189791d632c8Sgwr error = smbfs_smb_create(dnp, name, nmlen, &scred, &fid, disp, xattr); 18984bff34e3Sthurlow if (error) 18994bff34e3Sthurlow goto out; 19004bff34e3Sthurlow 19014bff34e3Sthurlow /* 19024bff34e3Sthurlow * XXX: Missing some code here to deal with 19034bff34e3Sthurlow * the case where we opened an existing file, 19044bff34e3Sthurlow * it's size is larger than 32-bits, and we're 19054bff34e3Sthurlow * setting the size from a process that's not 19064bff34e3Sthurlow * aware of large file offsets. i.e. 19074bff34e3Sthurlow * from the NFS3 code: 19084bff34e3Sthurlow */ 19094bff34e3Sthurlow #if NOT_YET /* XXX */ 19104bff34e3Sthurlow if ((vattr.va_mask & AT_SIZE) && 19114bff34e3Sthurlow vp->v_type == VREG) { 19124bff34e3Sthurlow np = VTOSMB(vp); 19134bff34e3Sthurlow /* 19144bff34e3Sthurlow * Check here for large file handled 19154bff34e3Sthurlow * by LF-unaware process (as 19164bff34e3Sthurlow * ufs_create() does) 19174bff34e3Sthurlow */ 19184bff34e3Sthurlow if (!(lfaware & FOFFMAX)) { 19194bff34e3Sthurlow mutex_enter(&np->r_statelock); 19204bff34e3Sthurlow if (np->r_size > MAXOFF32_T) 19214bff34e3Sthurlow error = EOVERFLOW; 19224bff34e3Sthurlow mutex_exit(&np->r_statelock); 19234bff34e3Sthurlow } 19244bff34e3Sthurlow if (!error) { 19254bff34e3Sthurlow vattr.va_mask = AT_SIZE; 19264bff34e3Sthurlow error = smbfssetattr(vp, 19274bff34e3Sthurlow &vattr, 0, cr); 19284bff34e3Sthurlow } 19294bff34e3Sthurlow } 19304bff34e3Sthurlow #endif /* XXX */ 19314bff34e3Sthurlow /* 19324bff34e3Sthurlow * Should use the fid to get/set the size 19334bff34e3Sthurlow * while we have it opened here. See above. 19344bff34e3Sthurlow */ 19354bff34e3Sthurlow 19364bff34e3Sthurlow cerror = smbfs_smb_close(smi->smi_share, fid, NULL, &scred); 19374bff34e3Sthurlow if (cerror) 19384bff34e3Sthurlow SMBERROR("error %d closing %s\\%s\n", 19394bff34e3Sthurlow cerror, dnp->n_rpath, name); 19404bff34e3Sthurlow 19414bff34e3Sthurlow /* 19424bff34e3Sthurlow * In the open case, the name may differ a little 19434bff34e3Sthurlow * from what we passed to create (case, etc.) 19444bff34e3Sthurlow * so call lookup to get the (opened) name. 19454bff34e3Sthurlow * 19464bff34e3Sthurlow * XXX: Could avoid this extra lookup if the 19474bff34e3Sthurlow * "createact" result from NT_CREATE says we 19484bff34e3Sthurlow * created the object. 19494bff34e3Sthurlow */ 19504bff34e3Sthurlow error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred); 19514bff34e3Sthurlow if (error) 19524bff34e3Sthurlow goto out; 19534bff34e3Sthurlow 19544bff34e3Sthurlow /* update attr and directory cache */ 19554bff34e3Sthurlow smbfs_attr_touchdir(dnp); 19564bff34e3Sthurlow 19574bff34e3Sthurlow error = smbfs_nget(dvp, name, nmlen, &fattr, &vp); 19584bff34e3Sthurlow if (error) 19594bff34e3Sthurlow goto out; 19604bff34e3Sthurlow 196191d632c8Sgwr #ifdef USE_DNLC 196291d632c8Sgwr dnlc_update(dvp, nm, vp); 19634bff34e3Sthurlow #endif 19644bff34e3Sthurlow 196591d632c8Sgwr /* XXX invalidate pages if we truncated? */ 196691d632c8Sgwr 19674bff34e3Sthurlow /* Success! */ 19684bff34e3Sthurlow *vpp = vp; 19694bff34e3Sthurlow error = 0; 19704bff34e3Sthurlow 19714bff34e3Sthurlow out: 19724bff34e3Sthurlow smb_credrele(&scred); 19734bff34e3Sthurlow if (name != nm) 19744bff34e3Sthurlow smbfs_name_free(name, nmlen); 19754bff34e3Sthurlow smbfs_rw_exit(&dnp->r_rwlock); 19764bff34e3Sthurlow return (error); 19774bff34e3Sthurlow } 19784bff34e3Sthurlow 19794bff34e3Sthurlow /* 19804bff34e3Sthurlow * XXX 19814bff34e3Sthurlow * This op should support the new FIGNORECASE flag for case-insensitive 19824bff34e3Sthurlow * lookups, per PSARC 2007/244. 19834bff34e3Sthurlow */ 19844bff34e3Sthurlow /* ARGSUSED */ 19854bff34e3Sthurlow static int 19864bff34e3Sthurlow smbfs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct, 19874bff34e3Sthurlow int flags) 19884bff34e3Sthurlow { 19894bff34e3Sthurlow int error; 19904bff34e3Sthurlow vnode_t *vp; 19914bff34e3Sthurlow smbnode_t *np; 19924bff34e3Sthurlow smbnode_t *dnp; 19934bff34e3Sthurlow struct smb_cred scred; 19944bff34e3Sthurlow /* enum smbfsstat status; */ 19954bff34e3Sthurlow smbmntinfo_t *smi; 19964bff34e3Sthurlow 19974bff34e3Sthurlow smi = VTOSMI(dvp); 19984bff34e3Sthurlow 19994bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 20004bff34e3Sthurlow return (EPERM); 20014bff34e3Sthurlow 20024bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 20034bff34e3Sthurlow return (EIO); 20044bff34e3Sthurlow 20054bff34e3Sthurlow dnp = VTOSMB(dvp); 20064bff34e3Sthurlow if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp))) 20074bff34e3Sthurlow return (EINTR); 20084bff34e3Sthurlow 20094bff34e3Sthurlow /* 20104bff34e3Sthurlow * Verify access to the dirctory. 20114bff34e3Sthurlow */ 20124bff34e3Sthurlow error = smbfs_access(dvp, VWRITE|VEXEC, 0, cr, ct); 20134bff34e3Sthurlow if (error) 20144bff34e3Sthurlow goto out; 20154bff34e3Sthurlow 20164bff34e3Sthurlow /* 20174bff34e3Sthurlow * NOTE: the darwin code gets the "vp" passed in so it looks 20184bff34e3Sthurlow * like the "vp" has probably been "lookup"ed by the VFS layer. 20194bff34e3Sthurlow * It looks like we will need to lookup the vp to check the 20204bff34e3Sthurlow * caches and check if the object being deleted is a directory. 20214bff34e3Sthurlow */ 20224bff34e3Sthurlow error = smbfslookup(dvp, nm, &vp, cr, 0, ct); 20234bff34e3Sthurlow if (error) 20244bff34e3Sthurlow goto out; 20254bff34e3Sthurlow 20264bff34e3Sthurlow /* Never allow link/unlink directories on CIFS. */ 20274bff34e3Sthurlow if (vp->v_type == VDIR) { 20284bff34e3Sthurlow VN_RELE(vp); 20294bff34e3Sthurlow error = EPERM; 20304bff34e3Sthurlow goto out; 20314bff34e3Sthurlow } 20324bff34e3Sthurlow 20334bff34e3Sthurlow /* 20344bff34e3Sthurlow * First just remove the entry from the name cache, as it 20354bff34e3Sthurlow * is most likely the only entry for this vp. 20364bff34e3Sthurlow */ 20374bff34e3Sthurlow dnlc_remove(dvp, nm); 20384bff34e3Sthurlow 20394bff34e3Sthurlow /* 20404bff34e3Sthurlow * If the file has a v_count > 1 then there may be more than one 20414bff34e3Sthurlow * entry in the name cache due multiple links or an open file, 20424bff34e3Sthurlow * but we don't have the real reference count so flush all 20434bff34e3Sthurlow * possible entries. 20444bff34e3Sthurlow */ 20454bff34e3Sthurlow if (vp->v_count > 1) 20464bff34e3Sthurlow dnlc_purge_vp(vp); 20474bff34e3Sthurlow 20484bff34e3Sthurlow /* 20494bff34e3Sthurlow * Now we have the real reference count on the vnode 20504bff34e3Sthurlow */ 20514bff34e3Sthurlow np = VTOSMB(vp); 20524bff34e3Sthurlow mutex_enter(&np->r_statelock); 20534bff34e3Sthurlow if (vp->v_count > 1) { 20544bff34e3Sthurlow /* 20554bff34e3Sthurlow * NFS does a rename on remove here. 20564bff34e3Sthurlow * Probably not applicable for SMB. 20574bff34e3Sthurlow * Like Darwin, just return EBUSY. 20584bff34e3Sthurlow * 20594bff34e3Sthurlow * XXX: Todo - Ask the server to set the 20604bff34e3Sthurlow * set the delete-on-close flag. 20614bff34e3Sthurlow */ 20624bff34e3Sthurlow mutex_exit(&np->r_statelock); 20634bff34e3Sthurlow error = EBUSY; 20644bff34e3Sthurlow } else { 20654bff34e3Sthurlow mutex_exit(&np->r_statelock); 20664bff34e3Sthurlow 2067613a2f6bSGordon Ross smb_credinit(&scred, cr); 20684bff34e3Sthurlow error = smbfs_smb_delete(np, &scred, NULL, 0, 0); 20694bff34e3Sthurlow smb_credrele(&scred); 20704bff34e3Sthurlow 20714bff34e3Sthurlow } 20724bff34e3Sthurlow 20734bff34e3Sthurlow VN_RELE(vp); 20744bff34e3Sthurlow 20754bff34e3Sthurlow out: 20764bff34e3Sthurlow smbfs_rw_exit(&dnp->r_rwlock); 20774bff34e3Sthurlow 20784bff34e3Sthurlow return (error); 20794bff34e3Sthurlow } 20804bff34e3Sthurlow 20814bff34e3Sthurlow 20824bff34e3Sthurlow /* 20834bff34e3Sthurlow * XXX 20844bff34e3Sthurlow * This op should support the new FIGNORECASE flag for case-insensitive 20854bff34e3Sthurlow * lookups, per PSARC 2007/244. 20864bff34e3Sthurlow */ 20874bff34e3Sthurlow /* ARGSUSED */ 20884bff34e3Sthurlow static int 20894bff34e3Sthurlow smbfs_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr, 20904bff34e3Sthurlow caller_context_t *ct, int flags) 20914bff34e3Sthurlow { 20924bff34e3Sthurlow /* vnode_t *realvp; */ 20934bff34e3Sthurlow 20944bff34e3Sthurlow if (curproc->p_zone != VTOSMI(odvp)->smi_zone || 20954bff34e3Sthurlow curproc->p_zone != VTOSMI(ndvp)->smi_zone) 20964bff34e3Sthurlow return (EPERM); 20974bff34e3Sthurlow 20984bff34e3Sthurlow if (VTOSMI(odvp)->smi_flags & SMI_DEAD || 20994bff34e3Sthurlow VTOSMI(ndvp)->smi_flags & SMI_DEAD || 21004bff34e3Sthurlow odvp->v_vfsp->vfs_flag & VFS_UNMOUNTED || 21014bff34e3Sthurlow ndvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 21024bff34e3Sthurlow return (EIO); 21034bff34e3Sthurlow 21044bff34e3Sthurlow return (smbfsrename(odvp, onm, ndvp, nnm, cr, ct)); 21054bff34e3Sthurlow } 21064bff34e3Sthurlow 21074bff34e3Sthurlow /* 21084bff34e3Sthurlow * smbfsrename does the real work of renaming in SMBFS 21094bff34e3Sthurlow */ 21104bff34e3Sthurlow /* ARGSUSED */ 21114bff34e3Sthurlow static int 21124bff34e3Sthurlow smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr, 21134bff34e3Sthurlow caller_context_t *ct) 21144bff34e3Sthurlow { 21154bff34e3Sthurlow int error; 21164bff34e3Sthurlow int nvp_locked = 0; 21174bff34e3Sthurlow vnode_t *nvp = NULL; 21184bff34e3Sthurlow vnode_t *ovp = NULL; 21194bff34e3Sthurlow smbnode_t *onp; 212091d632c8Sgwr smbnode_t *nnp; 21214bff34e3Sthurlow smbnode_t *odnp; 21224bff34e3Sthurlow smbnode_t *ndnp; 21234bff34e3Sthurlow struct smb_cred scred; 21244bff34e3Sthurlow /* enum smbfsstat status; */ 21254bff34e3Sthurlow 21264bff34e3Sthurlow ASSERT(curproc->p_zone == VTOSMI(odvp)->smi_zone); 21274bff34e3Sthurlow 21284bff34e3Sthurlow if (strcmp(onm, ".") == 0 || strcmp(onm, "..") == 0 || 21294bff34e3Sthurlow strcmp(nnm, ".") == 0 || strcmp(nnm, "..") == 0) 21304bff34e3Sthurlow return (EINVAL); 21314bff34e3Sthurlow 21324bff34e3Sthurlow /* 21334bff34e3Sthurlow * Check that everything is on the same filesystem. 21344bff34e3Sthurlow * vn_rename checks the fsid's, but in case we don't 21354bff34e3Sthurlow * fill those in correctly, check here too. 21364bff34e3Sthurlow */ 21374bff34e3Sthurlow if (odvp->v_vfsp != ndvp->v_vfsp) 21384bff34e3Sthurlow return (EXDEV); 21394bff34e3Sthurlow 21404bff34e3Sthurlow odnp = VTOSMB(odvp); 21414bff34e3Sthurlow ndnp = VTOSMB(ndvp); 21424bff34e3Sthurlow 21434bff34e3Sthurlow /* 21444bff34e3Sthurlow * Avoid deadlock here on old vs new directory nodes 21454bff34e3Sthurlow * by always taking the locks in order of address. 21464bff34e3Sthurlow * The order is arbitrary, but must be consistent. 21474bff34e3Sthurlow */ 21484bff34e3Sthurlow if (odnp < ndnp) { 21494bff34e3Sthurlow if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER, 21504bff34e3Sthurlow SMBINTR(odvp))) 21514bff34e3Sthurlow return (EINTR); 21524bff34e3Sthurlow if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER, 21534bff34e3Sthurlow SMBINTR(ndvp))) { 21544bff34e3Sthurlow smbfs_rw_exit(&odnp->r_rwlock); 21554bff34e3Sthurlow return (EINTR); 21564bff34e3Sthurlow } 21574bff34e3Sthurlow } else { 21584bff34e3Sthurlow if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER, 21594bff34e3Sthurlow SMBINTR(ndvp))) 21604bff34e3Sthurlow return (EINTR); 21614bff34e3Sthurlow if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER, 21624bff34e3Sthurlow SMBINTR(odvp))) { 21634bff34e3Sthurlow smbfs_rw_exit(&ndnp->r_rwlock); 21644bff34e3Sthurlow return (EINTR); 21654bff34e3Sthurlow } 21664bff34e3Sthurlow } 21674bff34e3Sthurlow /* 21684bff34e3Sthurlow * No returns after this point (goto out) 21694bff34e3Sthurlow */ 21704bff34e3Sthurlow 21714bff34e3Sthurlow /* 21724bff34e3Sthurlow * Need write access on source and target. 21734bff34e3Sthurlow * Server takes care of most checks. 21744bff34e3Sthurlow */ 21754bff34e3Sthurlow error = smbfs_access(odvp, VWRITE|VEXEC, 0, cr, ct); 21764bff34e3Sthurlow if (error) 21774bff34e3Sthurlow goto out; 21784bff34e3Sthurlow if (odvp != ndvp) { 21794bff34e3Sthurlow error = smbfs_access(ndvp, VWRITE, 0, cr, ct); 21804bff34e3Sthurlow if (error) 21814bff34e3Sthurlow goto out; 21824bff34e3Sthurlow } 21834bff34e3Sthurlow 21844bff34e3Sthurlow /* 21854bff34e3Sthurlow * Lookup the source name. Must already exist. 21864bff34e3Sthurlow */ 21874bff34e3Sthurlow error = smbfslookup(odvp, onm, &ovp, cr, 0, ct); 21884bff34e3Sthurlow if (error) 21894bff34e3Sthurlow goto out; 21904bff34e3Sthurlow 21914bff34e3Sthurlow /* 21924bff34e3Sthurlow * Lookup the target file. If it exists, it needs to be 21934bff34e3Sthurlow * checked to see whether it is a mount point and whether 21944bff34e3Sthurlow * it is active (open). 21954bff34e3Sthurlow */ 21964bff34e3Sthurlow error = smbfslookup(ndvp, nnm, &nvp, cr, 0, ct); 21974bff34e3Sthurlow if (!error) { 21984bff34e3Sthurlow /* 21994bff34e3Sthurlow * Target (nvp) already exists. Check that it 22004bff34e3Sthurlow * has the same type as the source. The server 22014bff34e3Sthurlow * will check this also, (and more reliably) but 22024bff34e3Sthurlow * this lets us return the correct error codes. 22034bff34e3Sthurlow */ 22044bff34e3Sthurlow if (ovp->v_type == VDIR) { 22054bff34e3Sthurlow if (nvp->v_type != VDIR) { 22064bff34e3Sthurlow error = ENOTDIR; 22074bff34e3Sthurlow goto out; 22084bff34e3Sthurlow } 22094bff34e3Sthurlow } else { 22104bff34e3Sthurlow if (nvp->v_type == VDIR) { 22114bff34e3Sthurlow error = EISDIR; 22124bff34e3Sthurlow goto out; 22134bff34e3Sthurlow } 22144bff34e3Sthurlow } 22154bff34e3Sthurlow 22164bff34e3Sthurlow /* 22174bff34e3Sthurlow * POSIX dictates that when the source and target 22184bff34e3Sthurlow * entries refer to the same file object, rename 22194bff34e3Sthurlow * must do nothing and exit without error. 22204bff34e3Sthurlow */ 22214bff34e3Sthurlow if (ovp == nvp) { 22224bff34e3Sthurlow error = 0; 22234bff34e3Sthurlow goto out; 22244bff34e3Sthurlow } 22254bff34e3Sthurlow 22264bff34e3Sthurlow /* 22274bff34e3Sthurlow * Also must ensure the target is not a mount point, 22284bff34e3Sthurlow * and keep mount/umount away until we're done. 22294bff34e3Sthurlow */ 22304bff34e3Sthurlow if (vn_vfsrlock(nvp)) { 22314bff34e3Sthurlow error = EBUSY; 22324bff34e3Sthurlow goto out; 22334bff34e3Sthurlow } 22344bff34e3Sthurlow nvp_locked = 1; 22354bff34e3Sthurlow if (vn_mountedvfs(nvp) != NULL) { 22364bff34e3Sthurlow error = EBUSY; 22374bff34e3Sthurlow goto out; 22384bff34e3Sthurlow } 22394bff34e3Sthurlow 22404bff34e3Sthurlow /* 22414bff34e3Sthurlow * Purge the name cache of all references to this vnode 22424bff34e3Sthurlow * so that we can check the reference count to infer 22434bff34e3Sthurlow * whether it is active or not. 22444bff34e3Sthurlow */ 22454bff34e3Sthurlow /* 22464bff34e3Sthurlow * First just remove the entry from the name cache, as it 22474bff34e3Sthurlow * is most likely the only entry for this vp. 22484bff34e3Sthurlow */ 22494bff34e3Sthurlow dnlc_remove(ndvp, nnm); 22504bff34e3Sthurlow /* 22514bff34e3Sthurlow * If the file has a v_count > 1 then there may be more 22524bff34e3Sthurlow * than one entry in the name cache due multiple links 22534bff34e3Sthurlow * or an open file, but we don't have the real reference 22544bff34e3Sthurlow * count so flush all possible entries. 22554bff34e3Sthurlow */ 22564bff34e3Sthurlow if (nvp->v_count > 1) 22574bff34e3Sthurlow dnlc_purge_vp(nvp); 225891d632c8Sgwr /* 225991d632c8Sgwr * when renaming directories to be a subdirectory of a 226091d632c8Sgwr * different parent, the dnlc entry for ".." will no 226191d632c8Sgwr * longer be valid, so it must be removed 226291d632c8Sgwr */ 226391d632c8Sgwr if (ndvp != odvp) { 226491d632c8Sgwr if (ovp->v_type == VDIR) { 226591d632c8Sgwr dnlc_remove(ovp, ".."); 226691d632c8Sgwr } 226791d632c8Sgwr } 226891d632c8Sgwr 226991d632c8Sgwr /* 227091d632c8Sgwr * CIFS gives a SHARING_VIOLATION error when 227191d632c8Sgwr * trying to rename onto an exising object, 227291d632c8Sgwr * so try to remove the target first. 227391d632c8Sgwr * (Only for files, not directories.) 227491d632c8Sgwr */ 227591d632c8Sgwr if (nvp->v_type == VDIR) { 227691d632c8Sgwr error = EEXIST; 227791d632c8Sgwr goto out; 227891d632c8Sgwr } 22794bff34e3Sthurlow 228091d632c8Sgwr /* 228142645588SGordon Ross * Nodes that are "not active" here have v_count=2 228242645588SGordon Ross * because vn_renameat (our caller) did a lookup on 228342645588SGordon Ross * both the source and target before this call. 228442645588SGordon Ross * Otherwise this similar to smbfs_remove. 228591d632c8Sgwr */ 228691d632c8Sgwr nnp = VTOSMB(nvp); 228791d632c8Sgwr mutex_enter(&nnp->r_statelock); 228891d632c8Sgwr if (nvp->v_count > 2) { 22894bff34e3Sthurlow /* 22904bff34e3Sthurlow * The target file exists, is not the same as 22914bff34e3Sthurlow * the source file, and is active. Other FS 22924bff34e3Sthurlow * implementations unlink the target here. 22934bff34e3Sthurlow * For SMB, we don't assume we can remove an 22944bff34e3Sthurlow * open file. Return an error instead. 22954bff34e3Sthurlow */ 229691d632c8Sgwr mutex_exit(&nnp->r_statelock); 229791d632c8Sgwr error = EBUSY; 22984bff34e3Sthurlow goto out; 22994bff34e3Sthurlow } 230091d632c8Sgwr mutex_exit(&nnp->r_statelock); 230191d632c8Sgwr 230291d632c8Sgwr /* 230391d632c8Sgwr * Target file is not active. Try to remove it. 230491d632c8Sgwr */ 2305613a2f6bSGordon Ross smb_credinit(&scred, cr); 230691d632c8Sgwr error = smbfs_smb_delete(nnp, &scred, NULL, 0, 0); 230791d632c8Sgwr smb_credrele(&scred); 230891d632c8Sgwr if (error) 230991d632c8Sgwr goto out; 231091d632c8Sgwr /* 231191d632c8Sgwr * OK, removed the target file. Continue as if 231291d632c8Sgwr * lookup target had failed (nvp == NULL). 231391d632c8Sgwr */ 231491d632c8Sgwr vn_vfsunlock(nvp); 231591d632c8Sgwr nvp_locked = 0; 231691d632c8Sgwr VN_RELE(nvp); 231791d632c8Sgwr nvp = NULL; 23184bff34e3Sthurlow } /* nvp */ 23194bff34e3Sthurlow 23204bff34e3Sthurlow dnlc_remove(odvp, onm); 23214bff34e3Sthurlow dnlc_remove(ndvp, nnm); 23224bff34e3Sthurlow 23234bff34e3Sthurlow onp = VTOSMB(ovp); 2324613a2f6bSGordon Ross smb_credinit(&scred, cr); 23254bff34e3Sthurlow error = smbfs_smb_rename(onp, ndnp, nnm, strlen(nnm), &scred); 23264bff34e3Sthurlow smb_credrele(&scred); 23274bff34e3Sthurlow 23284bff34e3Sthurlow 23294bff34e3Sthurlow out: 23304bff34e3Sthurlow if (nvp) { 23314bff34e3Sthurlow if (nvp_locked) 23324bff34e3Sthurlow vn_vfsunlock(nvp); 23334bff34e3Sthurlow VN_RELE(nvp); 23344bff34e3Sthurlow } 23354bff34e3Sthurlow if (ovp) 23364bff34e3Sthurlow VN_RELE(ovp); 23374bff34e3Sthurlow 23384bff34e3Sthurlow smbfs_rw_exit(&odnp->r_rwlock); 23394bff34e3Sthurlow smbfs_rw_exit(&ndnp->r_rwlock); 23404bff34e3Sthurlow 23414bff34e3Sthurlow return (error); 23424bff34e3Sthurlow } 23434bff34e3Sthurlow 23444bff34e3Sthurlow /* 23454bff34e3Sthurlow * XXX 23464bff34e3Sthurlow * vsecattr_t is new to build 77, and we need to eventually support 23474bff34e3Sthurlow * it in order to create an ACL when an object is created. 23484bff34e3Sthurlow * 23494bff34e3Sthurlow * This op should support the new FIGNORECASE flag for case-insensitive 23504bff34e3Sthurlow * lookups, per PSARC 2007/244. 23514bff34e3Sthurlow */ 23524bff34e3Sthurlow /* ARGSUSED */ 23534bff34e3Sthurlow static int 23544bff34e3Sthurlow smbfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp, 23554bff34e3Sthurlow cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp) 23564bff34e3Sthurlow { 23574bff34e3Sthurlow vnode_t *vp; 23584bff34e3Sthurlow struct smbnode *dnp = VTOSMB(dvp); 23594bff34e3Sthurlow struct smbmntinfo *smi = VTOSMI(dvp); 23604bff34e3Sthurlow struct smb_cred scred; 23614bff34e3Sthurlow struct smbfattr fattr; 23624bff34e3Sthurlow const char *name = (const char *) nm; 23634bff34e3Sthurlow int nmlen = strlen(name); 23644bff34e3Sthurlow int error, hiderr; 23654bff34e3Sthurlow 23664bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 23674bff34e3Sthurlow return (EPERM); 23684bff34e3Sthurlow 23694bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 23704bff34e3Sthurlow return (EIO); 23714bff34e3Sthurlow 23724bff34e3Sthurlow if ((nmlen == 1 && name[0] == '.') || 23734bff34e3Sthurlow (nmlen == 2 && name[0] == '.' && name[1] == '.')) 23744bff34e3Sthurlow return (EEXIST); 23754bff34e3Sthurlow 237691d632c8Sgwr /* Only plain files are allowed in V_XATTRDIR. */ 237791d632c8Sgwr if (dvp->v_flag & V_XATTRDIR) 237891d632c8Sgwr return (EINVAL); 237991d632c8Sgwr 23804bff34e3Sthurlow if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp))) 23814bff34e3Sthurlow return (EINTR); 2382613a2f6bSGordon Ross smb_credinit(&scred, cr); 23834bff34e3Sthurlow 23844bff34e3Sthurlow /* 23854bff34e3Sthurlow * XXX: Do we need r_lkserlock too? 23864bff34e3Sthurlow * No use of any shared fid or fctx... 23874bff34e3Sthurlow */ 23884bff34e3Sthurlow 23894bff34e3Sthurlow /* 23904bff34e3Sthurlow * Require write access in the containing directory. 23914bff34e3Sthurlow */ 23924bff34e3Sthurlow error = smbfs_access(dvp, VWRITE, 0, cr, ct); 23934bff34e3Sthurlow if (error) 23944bff34e3Sthurlow goto out; 23954bff34e3Sthurlow 239691d632c8Sgwr /* remove possible negative entry from the dnlc */ 239791d632c8Sgwr dnlc_remove(dvp, nm); 239891d632c8Sgwr 23994bff34e3Sthurlow error = smbfs_smb_mkdir(dnp, name, nmlen, &scred); 24004bff34e3Sthurlow if (error) 24014bff34e3Sthurlow goto out; 24024bff34e3Sthurlow 24034bff34e3Sthurlow error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred); 24044bff34e3Sthurlow if (error) 24054bff34e3Sthurlow goto out; 24064bff34e3Sthurlow 24074bff34e3Sthurlow smbfs_attr_touchdir(dnp); 24084bff34e3Sthurlow 24094bff34e3Sthurlow error = smbfs_nget(dvp, name, nmlen, &fattr, &vp); 24104bff34e3Sthurlow if (error) 24114bff34e3Sthurlow goto out; 24124bff34e3Sthurlow 241391d632c8Sgwr #ifdef USE_DNLC 241491d632c8Sgwr dnlc_update(dvp, nm, vp); 24154bff34e3Sthurlow #endif 24164bff34e3Sthurlow 24174bff34e3Sthurlow if (name[0] == '.') 24184bff34e3Sthurlow if ((hiderr = smbfs_smb_hideit(VTOSMB(vp), NULL, 0, &scred))) 24194bff34e3Sthurlow SMBVDEBUG("hide failure %d\n", hiderr); 24204bff34e3Sthurlow 24214bff34e3Sthurlow /* Success! */ 24224bff34e3Sthurlow *vpp = vp; 24234bff34e3Sthurlow error = 0; 24244bff34e3Sthurlow out: 24254bff34e3Sthurlow smb_credrele(&scred); 24264bff34e3Sthurlow smbfs_rw_exit(&dnp->r_rwlock); 24274bff34e3Sthurlow 24284bff34e3Sthurlow if (name != nm) 24294bff34e3Sthurlow smbfs_name_free(name, nmlen); 24304bff34e3Sthurlow 24314bff34e3Sthurlow return (error); 24324bff34e3Sthurlow } 24334bff34e3Sthurlow 24344bff34e3Sthurlow /* 24354bff34e3Sthurlow * XXX 24364bff34e3Sthurlow * This op should support the new FIGNORECASE flag for case-insensitive 24374bff34e3Sthurlow * lookups, per PSARC 2007/244. 24384bff34e3Sthurlow */ 24394bff34e3Sthurlow /* ARGSUSED */ 24404bff34e3Sthurlow static int 24414bff34e3Sthurlow smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr, 24424bff34e3Sthurlow caller_context_t *ct, int flags) 24434bff34e3Sthurlow { 24444bff34e3Sthurlow vnode_t *vp = NULL; 24454bff34e3Sthurlow int vp_locked = 0; 24464bff34e3Sthurlow struct smbmntinfo *smi = VTOSMI(dvp); 24474bff34e3Sthurlow struct smbnode *dnp = VTOSMB(dvp); 24484bff34e3Sthurlow struct smbnode *np; 24494bff34e3Sthurlow struct smb_cred scred; 24504bff34e3Sthurlow int error; 24514bff34e3Sthurlow 24524bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 24534bff34e3Sthurlow return (EPERM); 24544bff34e3Sthurlow 24554bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 24564bff34e3Sthurlow return (EIO); 24574bff34e3Sthurlow 24584bff34e3Sthurlow if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp))) 24594bff34e3Sthurlow return (EINTR); 2460613a2f6bSGordon Ross smb_credinit(&scred, cr); 24614bff34e3Sthurlow 24624bff34e3Sthurlow /* 24634bff34e3Sthurlow * Require w/x access in the containing directory. 24644bff34e3Sthurlow * Server handles all other access checks. 24654bff34e3Sthurlow */ 24664bff34e3Sthurlow error = smbfs_access(dvp, VEXEC|VWRITE, 0, cr, ct); 24674bff34e3Sthurlow if (error) 24684bff34e3Sthurlow goto out; 24694bff34e3Sthurlow 24704bff34e3Sthurlow /* 24714bff34e3Sthurlow * First lookup the entry to be removed. 24724bff34e3Sthurlow */ 24734bff34e3Sthurlow error = smbfslookup(dvp, nm, &vp, cr, 0, ct); 24744bff34e3Sthurlow if (error) 24754bff34e3Sthurlow goto out; 24764bff34e3Sthurlow np = VTOSMB(vp); 24774bff34e3Sthurlow 24784bff34e3Sthurlow /* 24794bff34e3Sthurlow * Disallow rmdir of "." or current dir, or the FS root. 24804bff34e3Sthurlow * Also make sure it's a directory, not a mount point, 24814bff34e3Sthurlow * and lock to keep mount/umount away until we're done. 24824bff34e3Sthurlow */ 24834bff34e3Sthurlow if ((vp == dvp) || (vp == cdir) || (vp->v_flag & VROOT)) { 24844bff34e3Sthurlow error = EINVAL; 24854bff34e3Sthurlow goto out; 24864bff34e3Sthurlow } 24874bff34e3Sthurlow if (vp->v_type != VDIR) { 24884bff34e3Sthurlow error = ENOTDIR; 24894bff34e3Sthurlow goto out; 24904bff34e3Sthurlow } 24914bff34e3Sthurlow if (vn_vfsrlock(vp)) { 24924bff34e3Sthurlow error = EBUSY; 24934bff34e3Sthurlow goto out; 24944bff34e3Sthurlow } 24954bff34e3Sthurlow vp_locked = 1; 24964bff34e3Sthurlow if (vn_mountedvfs(vp) != NULL) { 24974bff34e3Sthurlow error = EBUSY; 24984bff34e3Sthurlow goto out; 24994bff34e3Sthurlow } 25004bff34e3Sthurlow 250191d632c8Sgwr /* 250291d632c8Sgwr * First just remove the entry from the name cache, as it 250391d632c8Sgwr * is most likely an entry for this vp. 250491d632c8Sgwr */ 250591d632c8Sgwr dnlc_remove(dvp, nm); 250691d632c8Sgwr 250791d632c8Sgwr /* 250891d632c8Sgwr * If there vnode reference count is greater than one, then 250991d632c8Sgwr * there may be additional references in the DNLC which will 251091d632c8Sgwr * need to be purged. First, trying removing the entry for 251191d632c8Sgwr * the parent directory and see if that removes the additional 251291d632c8Sgwr * reference(s). If that doesn't do it, then use dnlc_purge_vp 251391d632c8Sgwr * to completely remove any references to the directory which 251491d632c8Sgwr * might still exist in the DNLC. 251591d632c8Sgwr */ 251691d632c8Sgwr if (vp->v_count > 1) { 251791d632c8Sgwr dnlc_remove(vp, ".."); 251891d632c8Sgwr if (vp->v_count > 1) 251991d632c8Sgwr dnlc_purge_vp(vp); 252091d632c8Sgwr } 252191d632c8Sgwr 25224bff34e3Sthurlow error = smbfs_smb_rmdir(np, &scred); 25234bff34e3Sthurlow if (error) 25244bff34e3Sthurlow goto out; 25254bff34e3Sthurlow 25264bff34e3Sthurlow mutex_enter(&np->r_statelock); 25274bff34e3Sthurlow dnp->n_flag |= NMODIFIED; 25284bff34e3Sthurlow mutex_exit(&np->r_statelock); 25294bff34e3Sthurlow smbfs_attr_touchdir(dnp); 25304bff34e3Sthurlow smb_rmhash(np); 25314bff34e3Sthurlow 25324bff34e3Sthurlow out: 25334bff34e3Sthurlow if (vp) { 25344bff34e3Sthurlow if (vp_locked) 25354bff34e3Sthurlow vn_vfsunlock(vp); 25364bff34e3Sthurlow VN_RELE(vp); 25374bff34e3Sthurlow } 25384bff34e3Sthurlow smb_credrele(&scred); 25394bff34e3Sthurlow smbfs_rw_exit(&dnp->r_rwlock); 25404bff34e3Sthurlow 25414bff34e3Sthurlow return (error); 25424bff34e3Sthurlow } 25434bff34e3Sthurlow 25444bff34e3Sthurlow 25454bff34e3Sthurlow /* ARGSUSED */ 25464bff34e3Sthurlow static int 25474bff34e3Sthurlow smbfs_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp, 25484bff34e3Sthurlow caller_context_t *ct, int flags) 25494bff34e3Sthurlow { 25504bff34e3Sthurlow struct smbnode *np = VTOSMB(vp); 25514bff34e3Sthurlow int error = 0; 25524bff34e3Sthurlow smbmntinfo_t *smi; 25534bff34e3Sthurlow 25544bff34e3Sthurlow smi = VTOSMI(vp); 25554bff34e3Sthurlow 25564bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 25574bff34e3Sthurlow return (EIO); 25584bff34e3Sthurlow 25594bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 25604bff34e3Sthurlow return (EIO); 25614bff34e3Sthurlow 25624bff34e3Sthurlow /* 25634bff34e3Sthurlow * Require read access in the directory. 25644bff34e3Sthurlow */ 25654bff34e3Sthurlow error = smbfs_access(vp, VREAD, 0, cr, ct); 25664bff34e3Sthurlow if (error) 25674bff34e3Sthurlow return (error); 25684bff34e3Sthurlow 25694bff34e3Sthurlow ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER)); 25704bff34e3Sthurlow 25714bff34e3Sthurlow /* 25724bff34e3Sthurlow * XXX: Todo readdir cache here 25734bff34e3Sthurlow * Note: NFS code is just below this. 25744bff34e3Sthurlow * 25754bff34e3Sthurlow * I am serializing the entire readdir opreation 25764bff34e3Sthurlow * now since we have not yet implemented readdir 25774bff34e3Sthurlow * cache. This fix needs to be revisited once 25784bff34e3Sthurlow * we implement readdir cache. 25794bff34e3Sthurlow */ 25804bff34e3Sthurlow if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp))) 25814bff34e3Sthurlow return (EINTR); 25824bff34e3Sthurlow 25834bff34e3Sthurlow error = smbfs_readvdir(vp, uiop, cr, eofp, ct); 25844bff34e3Sthurlow 25854bff34e3Sthurlow smbfs_rw_exit(&np->r_lkserlock); 25864bff34e3Sthurlow 25874bff34e3Sthurlow return (error); 25884bff34e3Sthurlow } 25894bff34e3Sthurlow 25904bff34e3Sthurlow /* ARGSUSED */ 25914bff34e3Sthurlow static int 25924bff34e3Sthurlow smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp, 25934bff34e3Sthurlow caller_context_t *ct) 25944bff34e3Sthurlow { 2595*5ecede33SGordon Ross /* 2596*5ecede33SGordon Ross * Note: "limit" tells the SMB-level FindFirst/FindNext 2597*5ecede33SGordon Ross * functions how many directory entries to request in 2598*5ecede33SGordon Ross * each OtW call. It needs to be large enough so that 2599*5ecede33SGordon Ross * we don't make lots of tiny OtW requests, but there's 2600*5ecede33SGordon Ross * no point making it larger than the maximum number of 2601*5ecede33SGordon Ross * OtW entries that would fit in a maximum sized trans2 2602*5ecede33SGordon Ross * response (64k / 48). Beyond that, it's just tuning. 2603*5ecede33SGordon Ross * WinNT used 512, Win2k used 1366. We use 1000. 2604*5ecede33SGordon Ross */ 2605*5ecede33SGordon Ross static const int limit = 1000; 2606*5ecede33SGordon Ross /* Largest possible dirent size. */ 2607*5ecede33SGordon Ross static const size_t dbufsiz = DIRENT64_RECLEN(SMB_MAXFNAMELEN); 26084bff34e3Sthurlow struct smb_cred scred; 26094bff34e3Sthurlow vnode_t *newvp; 26104bff34e3Sthurlow struct smbnode *np = VTOSMB(vp); 26114bff34e3Sthurlow struct smbfs_fctx *ctx; 2612*5ecede33SGordon Ross struct dirent64 *dp; 2613*5ecede33SGordon Ross ssize_t save_resid; 2614*5ecede33SGordon Ross offset_t save_offset; /* 64 bits */ 2615*5ecede33SGordon Ross int offset; /* yes, 32 bits */ 2616*5ecede33SGordon Ross int nmlen, error; 2617*5ecede33SGordon Ross ushort_t reclen; 26184bff34e3Sthurlow 26194bff34e3Sthurlow ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone); 26204bff34e3Sthurlow 26214bff34e3Sthurlow /* Make sure we serialize for n_dirseq use. */ 26224bff34e3Sthurlow ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_WRITER)); 26234bff34e3Sthurlow 2624*5ecede33SGordon Ross /* 2625*5ecede33SGordon Ross * Make sure smbfs_open filled in n_dirseq 2626*5ecede33SGordon Ross */ 2627*5ecede33SGordon Ross if (np->n_dirseq == NULL) 2628*5ecede33SGordon Ross return (EBADF); 2629*5ecede33SGordon Ross 2630*5ecede33SGordon Ross /* Check for overflow of (32-bit) directory offset. */ 2631*5ecede33SGordon Ross if (uio->uio_loffset < 0 || uio->uio_loffset > INT32_MAX || 2632*5ecede33SGordon Ross (uio->uio_loffset + uio->uio_resid) > INT32_MAX) 2633*5ecede33SGordon Ross return (EINVAL); 2634*5ecede33SGordon Ross 2635*5ecede33SGordon Ross /* Require space for at least one dirent. */ 2636*5ecede33SGordon Ross if (uio->uio_resid < dbufsiz) 26374bff34e3Sthurlow return (EINVAL); 26384bff34e3Sthurlow 2639*5ecede33SGordon Ross #ifdef USE_DNLC 26404bff34e3Sthurlow /* 26414bff34e3Sthurlow * This dnlc_purge_vp ensures that name cache for this dir will be 26424bff34e3Sthurlow * current - it'll only have the items for which the smbfs_nget 26434bff34e3Sthurlow * MAKEENTRY happened. 26444bff34e3Sthurlow */ 26454bff34e3Sthurlow if (smbfs_fastlookup) 26464bff34e3Sthurlow dnlc_purge_vp(vp); 26474bff34e3Sthurlow #endif 26484bff34e3Sthurlow SMBVDEBUG("dirname='%s'\n", np->n_rpath); 2649613a2f6bSGordon Ross smb_credinit(&scred, cr); 26504bff34e3Sthurlow dp = kmem_alloc(dbufsiz, KM_SLEEP); 26514bff34e3Sthurlow 2652*5ecede33SGordon Ross save_resid = uio->uio_resid; 2653*5ecede33SGordon Ross save_offset = uio->uio_loffset; 2654*5ecede33SGordon Ross offset = uio->uio_offset; 2655*5ecede33SGordon Ross SMBVDEBUG("in: offset=%d, resid=%d\n", 2656*5ecede33SGordon Ross (int)uio->uio_offset, (int)uio->uio_resid); 2657*5ecede33SGordon Ross error = 0; 26584bff34e3Sthurlow 26594bff34e3Sthurlow /* 26604bff34e3Sthurlow * Generate the "." and ".." entries here so we can 26614bff34e3Sthurlow * (1) make sure they appear (but only once), and 26624bff34e3Sthurlow * (2) deal with getting their I numbers which the 26634bff34e3Sthurlow * findnext below does only for normal names. 26644bff34e3Sthurlow */ 2665*5ecede33SGordon Ross while (offset < FIRST_DIROFS) { 2666*5ecede33SGordon Ross /* 2667*5ecede33SGordon Ross * Tricky bit filling in the first two: 2668*5ecede33SGordon Ross * offset 0 is ".", offset 1 is ".." 2669*5ecede33SGordon Ross * so strlen of these is offset+1. 2670*5ecede33SGordon Ross */ 26714bff34e3Sthurlow reclen = DIRENT64_RECLEN(offset + 1); 2672*5ecede33SGordon Ross if (uio->uio_resid < reclen) 2673*5ecede33SGordon Ross goto out; 26744bff34e3Sthurlow bzero(dp, reclen); 26754bff34e3Sthurlow dp->d_reclen = reclen; 26764bff34e3Sthurlow dp->d_name[0] = '.'; 26774bff34e3Sthurlow dp->d_name[1] = '.'; 26784bff34e3Sthurlow dp->d_name[offset + 1] = '\0'; 26794bff34e3Sthurlow /* 26804bff34e3Sthurlow * Want the real I-numbers for the "." and ".." 26814bff34e3Sthurlow * entries. For these two names, we know that 2682*5ecede33SGordon Ross * smbfslookup can get the nodes efficiently. 26834bff34e3Sthurlow */ 26844bff34e3Sthurlow error = smbfslookup(vp, dp->d_name, &newvp, cr, 1, ct); 26854bff34e3Sthurlow if (error) { 26864bff34e3Sthurlow dp->d_ino = np->n_ino + offset; /* fiction */ 26874bff34e3Sthurlow } else { 26884bff34e3Sthurlow dp->d_ino = VTOSMB(newvp)->n_ino; 26894bff34e3Sthurlow VN_RELE(newvp); 26904bff34e3Sthurlow } 2691*5ecede33SGordon Ross /* 2692*5ecede33SGordon Ross * Note: d_off is the offset that a user-level program 2693*5ecede33SGordon Ross * should seek to for reading the NEXT directory entry. 2694*5ecede33SGordon Ross * See libc: readdir, telldir, seekdir 2695*5ecede33SGordon Ross */ 2696*5ecede33SGordon Ross dp->d_off = offset + 1; 2697*5ecede33SGordon Ross error = uiomove(dp, reclen, UIO_READ, uio); 26984bff34e3Sthurlow if (error) 26994bff34e3Sthurlow goto out; 2700*5ecede33SGordon Ross /* 2701*5ecede33SGordon Ross * Note: uiomove updates uio->uio_offset, 2702*5ecede33SGordon Ross * but we want it to be our "cookie" value, 2703*5ecede33SGordon Ross * which just counts dirents ignoring size. 2704*5ecede33SGordon Ross */ 27054bff34e3Sthurlow uio->uio_offset = ++offset; 27064bff34e3Sthurlow } 2707*5ecede33SGordon Ross 2708*5ecede33SGordon Ross /* 2709*5ecede33SGordon Ross * If there was a backward seek, we have to reopen. 2710*5ecede33SGordon Ross */ 2711*5ecede33SGordon Ross if (offset < np->n_dirofs) { 2712*5ecede33SGordon Ross SMBVDEBUG("Reopening search %d:%d\n", 2713*5ecede33SGordon Ross offset, np->n_dirofs); 27144bff34e3Sthurlow error = smbfs_smb_findopen(np, "*", 1, 27154bff34e3Sthurlow SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR, 27164bff34e3Sthurlow &scred, &ctx); 27174bff34e3Sthurlow if (error) { 27184bff34e3Sthurlow SMBVDEBUG("can not open search, error = %d", error); 27194bff34e3Sthurlow goto out; 27204bff34e3Sthurlow } 2721*5ecede33SGordon Ross /* free the old one */ 2722*5ecede33SGordon Ross (void) smbfs_smb_findclose(np->n_dirseq, &scred); 2723*5ecede33SGordon Ross /* save the new one */ 27244bff34e3Sthurlow np->n_dirseq = ctx; 2725*5ecede33SGordon Ross np->n_dirofs = FIRST_DIROFS; 2726*5ecede33SGordon Ross } else { 27274bff34e3Sthurlow ctx = np->n_dirseq; 2728*5ecede33SGordon Ross } 2729*5ecede33SGordon Ross 2730*5ecede33SGordon Ross /* 2731*5ecede33SGordon Ross * Skip entries before the requested offset. 2732*5ecede33SGordon Ross */ 27334bff34e3Sthurlow while (np->n_dirofs < offset) { 2734*5ecede33SGordon Ross error = smbfs_smb_findnext(ctx, limit, &scred); 2735*5ecede33SGordon Ross if (error != 0) 27364bff34e3Sthurlow goto out; 2737*5ecede33SGordon Ross np->n_dirofs++; 27384bff34e3Sthurlow } 2739*5ecede33SGordon Ross 2740*5ecede33SGordon Ross /* 2741*5ecede33SGordon Ross * While there's room in the caller's buffer: 2742*5ecede33SGordon Ross * get a directory entry from SMB, 2743*5ecede33SGordon Ross * convert to a dirent, copyout. 2744*5ecede33SGordon Ross * We stop when there is no longer room for a 2745*5ecede33SGordon Ross * maximum sized dirent because we must decide 2746*5ecede33SGordon Ross * before we know anything about the next entry. 2747*5ecede33SGordon Ross */ 2748*5ecede33SGordon Ross while (uio->uio_resid >= dbufsiz) { 27494bff34e3Sthurlow error = smbfs_smb_findnext(ctx, limit, &scred); 2750*5ecede33SGordon Ross if (error != 0) 2751*5ecede33SGordon Ross goto out; 27524bff34e3Sthurlow np->n_dirofs++; 2753*5ecede33SGordon Ross 27544bff34e3Sthurlow /* Sanity check the name length. */ 27554bff34e3Sthurlow nmlen = ctx->f_nmlen; 2756613a2f6bSGordon Ross if (nmlen > SMB_MAXFNAMELEN) { 2757613a2f6bSGordon Ross nmlen = SMB_MAXFNAMELEN; 27584bff34e3Sthurlow SMBVDEBUG("Truncating name: %s\n", ctx->f_name); 27594bff34e3Sthurlow } 27604bff34e3Sthurlow #ifdef NOT_YET 27614bff34e3Sthurlow if (smbfs_fastlookup) { 2762*5ecede33SGordon Ross if (smbfs_nget(vp, ctx->f_name, nmlen, 2763*5ecede33SGordon Ross &ctx->f_attr, &newvp) == 0) 27644bff34e3Sthurlow VN_RELE(newvp); 27654bff34e3Sthurlow } 27664bff34e3Sthurlow #endif /* NOT_YET */ 2767*5ecede33SGordon Ross 2768*5ecede33SGordon Ross reclen = DIRENT64_RECLEN(nmlen); 2769*5ecede33SGordon Ross bzero(dp, reclen); 2770*5ecede33SGordon Ross dp->d_reclen = reclen; 2771*5ecede33SGordon Ross bcopy(ctx->f_name, dp->d_name, nmlen); 2772*5ecede33SGordon Ross dp->d_name[nmlen] = '\0'; 2773*5ecede33SGordon Ross dp->d_ino = ctx->f_attr.fa_ino; 2774*5ecede33SGordon Ross dp->d_off = offset + 1; /* See d_off comment above */ 2775*5ecede33SGordon Ross error = uiomove(dp, reclen, UIO_READ, uio); 27764bff34e3Sthurlow if (error) 2777*5ecede33SGordon Ross goto out; 2778*5ecede33SGordon Ross /* See comment re. uio_offset above. */ 27794bff34e3Sthurlow uio->uio_offset = ++offset; 27804bff34e3Sthurlow } 2781*5ecede33SGordon Ross 27824bff34e3Sthurlow out: 2783*5ecede33SGordon Ross /* 2784*5ecede33SGordon Ross * When we come to the end of a directory, the 2785*5ecede33SGordon Ross * SMB-level functions return ENOENT, but the 2786*5ecede33SGordon Ross * caller is not expecting an error return. 2787*5ecede33SGordon Ross * 2788*5ecede33SGordon Ross * Also note that we must delay the call to 2789*5ecede33SGordon Ross * smbfs_smb_findclose(np->n_dirseq, ...) 2790*5ecede33SGordon Ross * until smbfs_close so that all reads at the 2791*5ecede33SGordon Ross * end of the directory will return no data. 2792*5ecede33SGordon Ross */ 2793*5ecede33SGordon Ross if (error == ENOENT) { 2794*5ecede33SGordon Ross error = 0; 2795*5ecede33SGordon Ross if (eofp) 2796*5ecede33SGordon Ross *eofp = 1; 2797*5ecede33SGordon Ross } 2798*5ecede33SGordon Ross /* 2799*5ecede33SGordon Ross * If we encountered an error (i.e. "access denied") 2800*5ecede33SGordon Ross * from the FindFirst call, we will have copied out 2801*5ecede33SGordon Ross * the "." and ".." entries leaving offset == 2. 2802*5ecede33SGordon Ross * In that case, restore the original offset/resid 2803*5ecede33SGordon Ross * so the caller gets no data with the error. 2804*5ecede33SGordon Ross */ 2805*5ecede33SGordon Ross if (error != 0 && offset == FIRST_DIROFS) { 2806*5ecede33SGordon Ross uio->uio_loffset = save_offset; 2807*5ecede33SGordon Ross uio->uio_resid = save_resid; 2808*5ecede33SGordon Ross } 2809*5ecede33SGordon Ross SMBVDEBUG("out: offset=%d, resid=%d\n", 2810*5ecede33SGordon Ross (int)uio->uio_offset, (int)uio->uio_resid); 2811*5ecede33SGordon Ross 28124bff34e3Sthurlow kmem_free(dp, dbufsiz); 28134bff34e3Sthurlow smb_credrele(&scred); 28144bff34e3Sthurlow return (error); 28154bff34e3Sthurlow } 28164bff34e3Sthurlow 28174bff34e3Sthurlow 28184bff34e3Sthurlow /* 28194bff34e3Sthurlow * The pair of functions VOP_RWLOCK, VOP_RWUNLOCK 28204bff34e3Sthurlow * are optional functions that are called by: 28214bff34e3Sthurlow * getdents, before/after VOP_READDIR 28224bff34e3Sthurlow * pread, before/after ... VOP_READ 28234bff34e3Sthurlow * pwrite, before/after ... VOP_WRITE 28244bff34e3Sthurlow * (other places) 28254bff34e3Sthurlow * 28264bff34e3Sthurlow * Careful here: None of the above check for any 28274bff34e3Sthurlow * error returns from VOP_RWLOCK / VOP_RWUNLOCK! 28284bff34e3Sthurlow * In fact, the return value from _rwlock is NOT 28294bff34e3Sthurlow * an error code, but V_WRITELOCK_TRUE / _FALSE. 28304bff34e3Sthurlow * 28314bff34e3Sthurlow * Therefore, it's up to _this_ code to make sure 28324bff34e3Sthurlow * the lock state remains balanced, which means 28334bff34e3Sthurlow * we can't "bail out" on interrupts, etc. 28344bff34e3Sthurlow */ 28354bff34e3Sthurlow 28364bff34e3Sthurlow /* ARGSUSED2 */ 28374bff34e3Sthurlow static int 28384bff34e3Sthurlow smbfs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp) 28394bff34e3Sthurlow { 28404bff34e3Sthurlow smbnode_t *np = VTOSMB(vp); 28414bff34e3Sthurlow 28424bff34e3Sthurlow if (!write_lock) { 28434bff34e3Sthurlow (void) smbfs_rw_enter_sig(&np->r_rwlock, RW_READER, FALSE); 28444bff34e3Sthurlow return (V_WRITELOCK_FALSE); 28454bff34e3Sthurlow } 28464bff34e3Sthurlow 28474bff34e3Sthurlow 28484bff34e3Sthurlow (void) smbfs_rw_enter_sig(&np->r_rwlock, RW_WRITER, FALSE); 28494bff34e3Sthurlow return (V_WRITELOCK_TRUE); 28504bff34e3Sthurlow } 28514bff34e3Sthurlow 28524bff34e3Sthurlow /* ARGSUSED */ 28534bff34e3Sthurlow static void 28544bff34e3Sthurlow smbfs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp) 28554bff34e3Sthurlow { 28564bff34e3Sthurlow smbnode_t *np = VTOSMB(vp); 28574bff34e3Sthurlow 28584bff34e3Sthurlow smbfs_rw_exit(&np->r_rwlock); 28594bff34e3Sthurlow } 28604bff34e3Sthurlow 28614bff34e3Sthurlow 28624bff34e3Sthurlow /* ARGSUSED */ 28634bff34e3Sthurlow static int 28644bff34e3Sthurlow smbfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct) 28654bff34e3Sthurlow { 28664bff34e3Sthurlow smbmntinfo_t *smi; 28674bff34e3Sthurlow 28684bff34e3Sthurlow smi = VTOSMI(vp); 28694bff34e3Sthurlow 28704bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 28714bff34e3Sthurlow return (EPERM); 28724bff34e3Sthurlow 28734bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 28744bff34e3Sthurlow return (EIO); 28754bff34e3Sthurlow 28764bff34e3Sthurlow /* 28774bff34e3Sthurlow * Because we stuff the readdir cookie into the offset field 28784bff34e3Sthurlow * someone may attempt to do an lseek with the cookie which 28794bff34e3Sthurlow * we want to succeed. 28804bff34e3Sthurlow */ 28814bff34e3Sthurlow if (vp->v_type == VDIR) 28824bff34e3Sthurlow return (0); 28834bff34e3Sthurlow 28844bff34e3Sthurlow /* Like NFS3, just check for 63-bit overflow. */ 28854bff34e3Sthurlow if (*noffp < 0) 28864bff34e3Sthurlow return (EINVAL); 28874bff34e3Sthurlow 28884bff34e3Sthurlow return (0); 28894bff34e3Sthurlow } 28904bff34e3Sthurlow 28914bff34e3Sthurlow 28924bff34e3Sthurlow /* 28934bff34e3Sthurlow * XXX 28944bff34e3Sthurlow * This op may need to support PSARC 2007/440, nbmand changes for CIFS Service. 28954bff34e3Sthurlow */ 28964bff34e3Sthurlow static int 28974bff34e3Sthurlow smbfs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag, 28984bff34e3Sthurlow offset_t offset, struct flk_callback *flk_cbp, cred_t *cr, 28994bff34e3Sthurlow caller_context_t *ct) 29004bff34e3Sthurlow { 29014bff34e3Sthurlow if (curproc->p_zone != VTOSMI(vp)->smi_zone) 29024bff34e3Sthurlow return (EIO); 29034bff34e3Sthurlow 29044bff34e3Sthurlow if (VTOSMI(vp)->smi_flags & SMI_LLOCK) 29054bff34e3Sthurlow return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct)); 29064bff34e3Sthurlow else 29074bff34e3Sthurlow return (ENOSYS); 29084bff34e3Sthurlow } 29094bff34e3Sthurlow 29104bff34e3Sthurlow /* 29114bff34e3Sthurlow * Free storage space associated with the specified vnode. The portion 29124bff34e3Sthurlow * to be freed is specified by bfp->l_start and bfp->l_len (already 29134bff34e3Sthurlow * normalized to a "whence" of 0). 29144bff34e3Sthurlow * 29154bff34e3Sthurlow * Called by fcntl(fd, F_FREESP, lkp) for libc:ftruncate, etc. 29164bff34e3Sthurlow */ 29174bff34e3Sthurlow /* ARGSUSED */ 29184bff34e3Sthurlow static int 29194bff34e3Sthurlow smbfs_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag, 29204bff34e3Sthurlow offset_t offset, cred_t *cr, caller_context_t *ct) 29214bff34e3Sthurlow { 29224bff34e3Sthurlow int error; 29234bff34e3Sthurlow smbmntinfo_t *smi; 29244bff34e3Sthurlow 29254bff34e3Sthurlow smi = VTOSMI(vp); 29264bff34e3Sthurlow 29274bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 29284bff34e3Sthurlow return (EIO); 29294bff34e3Sthurlow 29304bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 29314bff34e3Sthurlow return (EIO); 29324bff34e3Sthurlow 293391d632c8Sgwr /* Caller (fcntl) has checked v_type */ 29344bff34e3Sthurlow ASSERT(vp->v_type == VREG); 29354bff34e3Sthurlow if (cmd != F_FREESP) 29364bff34e3Sthurlow return (EINVAL); 29374bff34e3Sthurlow 29384bff34e3Sthurlow /* 29394bff34e3Sthurlow * Like NFS3, no 32-bit offset checks here. 29404bff34e3Sthurlow * Our SMB layer takes care to return EFBIG 29414bff34e3Sthurlow * when it has to fallback to a 32-bit call. 29424bff34e3Sthurlow */ 29434bff34e3Sthurlow 29444bff34e3Sthurlow error = convoff(vp, bfp, 0, offset); 29454bff34e3Sthurlow if (!error) { 29464bff34e3Sthurlow ASSERT(bfp->l_start >= 0); 29474bff34e3Sthurlow if (bfp->l_len == 0) { 29484bff34e3Sthurlow struct vattr va; 29494bff34e3Sthurlow 29504bff34e3Sthurlow /* 29514bff34e3Sthurlow * ftruncate should not change the ctime and 29524bff34e3Sthurlow * mtime if we truncate the file to its 29534bff34e3Sthurlow * previous size. 29544bff34e3Sthurlow */ 29554bff34e3Sthurlow va.va_mask = AT_SIZE; 29564bff34e3Sthurlow error = smbfsgetattr(vp, &va, cr); 29574bff34e3Sthurlow if (error || va.va_size == bfp->l_start) 29584bff34e3Sthurlow return (error); 29594bff34e3Sthurlow va.va_mask = AT_SIZE; 29604bff34e3Sthurlow va.va_size = bfp->l_start; 29614bff34e3Sthurlow error = smbfssetattr(vp, &va, 0, cr); 29624bff34e3Sthurlow } else 29634bff34e3Sthurlow error = EINVAL; 29644bff34e3Sthurlow } 29654bff34e3Sthurlow 29664bff34e3Sthurlow return (error); 29674bff34e3Sthurlow } 29684bff34e3Sthurlow 29694bff34e3Sthurlow /* ARGSUSED */ 29704bff34e3Sthurlow static int 29714bff34e3Sthurlow smbfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr, 29724bff34e3Sthurlow caller_context_t *ct) 29734bff34e3Sthurlow { 297491d632c8Sgwr vfs_t *vfs; 29754bff34e3Sthurlow smbmntinfo_t *smi; 29764bff34e3Sthurlow struct smb_share *ssp; 29774bff34e3Sthurlow 297891d632c8Sgwr vfs = vp->v_vfsp; 297991d632c8Sgwr smi = VFTOSMI(vfs); 29804bff34e3Sthurlow 29814bff34e3Sthurlow if (curproc->p_zone != smi->smi_zone) 29824bff34e3Sthurlow return (EIO); 29834bff34e3Sthurlow 29844bff34e3Sthurlow if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) 29854bff34e3Sthurlow return (EIO); 29864bff34e3Sthurlow 29874bff34e3Sthurlow switch (cmd) { 29884bff34e3Sthurlow case _PC_FILESIZEBITS: 29894bff34e3Sthurlow ssp = smi->smi_share; 29904bff34e3Sthurlow if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES) 29914bff34e3Sthurlow *valp = 64; 29924bff34e3Sthurlow else 29934bff34e3Sthurlow *valp = 32; 29944bff34e3Sthurlow break; 29954bff34e3Sthurlow 29964bff34e3Sthurlow case _PC_LINK_MAX: 29974bff34e3Sthurlow /* We only ever report one link to an object */ 29984bff34e3Sthurlow *valp = 1; 29994bff34e3Sthurlow break; 30004bff34e3Sthurlow 30017568150aSgwr case _PC_ACL_ENABLED: 30027568150aSgwr /* 30037568150aSgwr * Always say "yes" here. Our _getsecattr 30047568150aSgwr * will build a trivial ACL when needed, 30057568150aSgwr * i.e. when server does not have ACLs. 30067568150aSgwr */ 30077568150aSgwr *valp = _ACL_ACE_ENABLED; 30087568150aSgwr break; 30097568150aSgwr 30104bff34e3Sthurlow case _PC_SYMLINK_MAX: /* No symlinks until we do Unix extensions */ 30114bff34e3Sthurlow *valp = 0; 30124bff34e3Sthurlow break; 30134bff34e3Sthurlow 301491d632c8Sgwr case _PC_XATTR_EXISTS: 301591d632c8Sgwr if (vfs->vfs_flag & VFS_XATTR) { 301691d632c8Sgwr *valp = smbfs_xa_exists(vp, cr); 301791d632c8Sgwr break; 301891d632c8Sgwr } 301991d632c8Sgwr return (EINVAL); 302091d632c8Sgwr 30214bff34e3Sthurlow default: 30224bff34e3Sthurlow return (fs_pathconf(vp, cmd, valp, cr, ct)); 30234bff34e3Sthurlow } 30244bff34e3Sthurlow return (0); 30254bff34e3Sthurlow } 30264bff34e3Sthurlow 30277568150aSgwr /* ARGSUSED */ 30287568150aSgwr static int 30297568150aSgwr smbfs_getsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr, 30307568150aSgwr caller_context_t *ct) 30317568150aSgwr { 30327568150aSgwr vfs_t *vfsp; 30337568150aSgwr smbmntinfo_t *smi; 30347568150aSgwr int error, uid, gid; 30357568150aSgwr uint_t mask; 30367568150aSgwr 30377568150aSgwr vfsp = vp->v_vfsp; 30387568150aSgwr smi = VFTOSMI(vfsp); 30397568150aSgwr 30407568150aSgwr if (curproc->p_zone != smi->smi_zone) 30417568150aSgwr return (EIO); 30427568150aSgwr 30437568150aSgwr if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 30447568150aSgwr return (EIO); 30457568150aSgwr 30467568150aSgwr /* 30477568150aSgwr * Our _pathconf indicates _ACL_ACE_ENABLED, 30487568150aSgwr * so we should only see VSA_ACE, etc here. 30497568150aSgwr * Note: vn_create asks for VSA_DFACLCNT, 30507568150aSgwr * and it expects ENOSYS and empty data. 30517568150aSgwr */ 30527568150aSgwr mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT | 30537568150aSgwr VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES); 30547568150aSgwr if (mask == 0) 30557568150aSgwr return (ENOSYS); 30567568150aSgwr 30577568150aSgwr /* XXX - access check ACE_READ_ACL? */ 30587568150aSgwr 30597568150aSgwr if (smi->smi_fsattr & FILE_PERSISTENT_ACLS) { 30607568150aSgwr error = smbfs_getacl(vp, vsa, &uid, &gid, flag, cr); 30617568150aSgwr /* XXX: Save uid/gid somewhere? */ 30627568150aSgwr } else 30637568150aSgwr error = ENOSYS; 30647568150aSgwr 30657568150aSgwr if (error == ENOSYS) 30667568150aSgwr error = fs_fab_acl(vp, vsa, flag, cr, ct); 30677568150aSgwr 30687568150aSgwr return (error); 30697568150aSgwr } 30707568150aSgwr 30717568150aSgwr /* ARGSUSED */ 30727568150aSgwr static int 30737568150aSgwr smbfs_setsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr, 30747568150aSgwr caller_context_t *ct) 30757568150aSgwr { 30767568150aSgwr vfs_t *vfsp; 30777568150aSgwr smbmntinfo_t *smi; 30787568150aSgwr int error; 30797568150aSgwr uint_t mask; 30807568150aSgwr 30817568150aSgwr vfsp = vp->v_vfsp; 30827568150aSgwr smi = VFTOSMI(vfsp); 30837568150aSgwr 30847568150aSgwr if (curproc->p_zone != smi->smi_zone) 30857568150aSgwr return (EIO); 30867568150aSgwr 30877568150aSgwr if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) 30887568150aSgwr return (EIO); 30897568150aSgwr 30907568150aSgwr /* 30917568150aSgwr * Our _pathconf indicates _ACL_ACE_ENABLED, 30927568150aSgwr * so we should only see VSA_ACE, etc here. 30937568150aSgwr */ 30947568150aSgwr mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT); 30957568150aSgwr if (mask == 0) 30967568150aSgwr return (ENOSYS); 30977568150aSgwr 30987568150aSgwr /* 30997568150aSgwr * If and when smbfs_access is extended, we can 31007568150aSgwr * check ACE_WRITE_ACL here instead. (XXX todo) 31017568150aSgwr * For now, in-line parts of smbfs_access, 31027568150aSgwr * i.e. only allow _setacl by the owner, 31037568150aSgwr * and check for read-only FS. 31047568150aSgwr */ 31057568150aSgwr if (vfsp->vfs_flag & VFS_RDONLY) 31067568150aSgwr return (EROFS); 31077568150aSgwr if (crgetuid(cr) != smi->smi_args.uid) 31087568150aSgwr return (EACCES); 31097568150aSgwr 31107568150aSgwr if (smi->smi_fsattr & FILE_PERSISTENT_ACLS) { 31117568150aSgwr error = smbfs_setacl(vp, vsa, -1, -1, flag, cr); 31127568150aSgwr } else 31137568150aSgwr error = ENOSYS; 31147568150aSgwr 31157568150aSgwr return (error); 31167568150aSgwr } 31174bff34e3Sthurlow 31184bff34e3Sthurlow 31194bff34e3Sthurlow /* 31204bff34e3Sthurlow * XXX 31214bff34e3Sthurlow * This op should eventually support PSARC 2007/268. 31224bff34e3Sthurlow */ 31234bff34e3Sthurlow static int 31244bff34e3Sthurlow smbfs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr, 31254bff34e3Sthurlow caller_context_t *ct) 31264bff34e3Sthurlow { 31274bff34e3Sthurlow if (curproc->p_zone != VTOSMI(vp)->smi_zone) 31284bff34e3Sthurlow return (EIO); 31294bff34e3Sthurlow 31304bff34e3Sthurlow if (VTOSMI(vp)->smi_flags & SMI_LLOCK) 31314bff34e3Sthurlow return (fs_shrlock(vp, cmd, shr, flag, cr, ct)); 31324bff34e3Sthurlow else 31334bff34e3Sthurlow return (ENOSYS); 31344bff34e3Sthurlow } 3135