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