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 /*
364bff34e3Sthurlow  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
374bff34e3Sthurlow  * Use is subject to license terms.
384bff34e3Sthurlow  */
394bff34e3Sthurlow 
404bff34e3Sthurlow #pragma ident	"%Z%%M%	%I%	%E% SMI"
414bff34e3Sthurlow 
424bff34e3Sthurlow #include <sys/systm.h>
434bff34e3Sthurlow #include <sys/cred.h>
444bff34e3Sthurlow #include <sys/vnode.h>
454bff34e3Sthurlow #include <sys/vfs.h>
46*7568150aSgwr #include <sys/filio.h>
474bff34e3Sthurlow #include <sys/uio.h>
484bff34e3Sthurlow #include <sys/dirent.h>
494bff34e3Sthurlow #include <sys/errno.h>
504bff34e3Sthurlow #include <sys/sysmacros.h>
514bff34e3Sthurlow #include <sys/kmem.h>
524bff34e3Sthurlow #include <sys/cmn_err.h>
534bff34e3Sthurlow #include <sys/dnlc.h>
544bff34e3Sthurlow #include <sys/vfs_opreg.h>
554bff34e3Sthurlow #include <sys/policy.h>
564bff34e3Sthurlow 
574bff34e3Sthurlow #include <netsmb/smb_osdep.h>
584bff34e3Sthurlow #include <netsmb/smb.h>
594bff34e3Sthurlow #include <netsmb/smb_conn.h>
604bff34e3Sthurlow #include <netsmb/smb_subr.h>
614bff34e3Sthurlow 
624bff34e3Sthurlow #include <smbfs/smbfs.h>
634bff34e3Sthurlow #include <smbfs/smbfs_node.h>
644bff34e3Sthurlow #include <smbfs/smbfs_subr.h>
654bff34e3Sthurlow 
66*7568150aSgwr #include <sys/fs/smbfs_ioctl.h>
674bff34e3Sthurlow #include <fs/fs_subr.h>
684bff34e3Sthurlow 
694bff34e3Sthurlow /*
704bff34e3Sthurlow  * These characters are illegal in NTFS file names.
714bff34e3Sthurlow  * ref: http://support.microsoft.com/kb/147438
724bff34e3Sthurlow  */
734bff34e3Sthurlow static const char illegal_chars[] = {
744bff34e3Sthurlow 	'\\',	/* back slash */
754bff34e3Sthurlow 	'/',	/* slash */
764bff34e3Sthurlow 	':',	/* colon */
774bff34e3Sthurlow 	'*',	/* asterisk */
784bff34e3Sthurlow 	'?',	/* question mark */
794bff34e3Sthurlow 	'"',	/* double quote */
804bff34e3Sthurlow 	'<',	/* less than sign */
814bff34e3Sthurlow 	'>',	/* greater than sign */
824bff34e3Sthurlow 	'|',	/* vertical bar */
834bff34e3Sthurlow 	0
844bff34e3Sthurlow };
854bff34e3Sthurlow 
864bff34e3Sthurlow /*
874bff34e3Sthurlow  * Turning this on causes nodes to be created in the cache
884bff34e3Sthurlow  * during directory listings.  The "fast" claim is debatable,
894bff34e3Sthurlow  * and the effects on the cache can be undesirable.
904bff34e3Sthurlow  */
914bff34e3Sthurlow 
924bff34e3Sthurlow /* local static function defines */
934bff34e3Sthurlow 
944bff34e3Sthurlow static int	smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr,
954bff34e3Sthurlow 			int dnlc, caller_context_t *);
964bff34e3Sthurlow static int	smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm,
974bff34e3Sthurlow 			cred_t *cr, caller_context_t *);
984bff34e3Sthurlow static int	smbfssetattr(vnode_t *, struct vattr *, int, cred_t *);
994bff34e3Sthurlow static int	smbfs_accessx(void *, int, cred_t *);
1004bff34e3Sthurlow static int	smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
1014bff34e3Sthurlow 			caller_context_t *);
1024bff34e3Sthurlow /*
1034bff34e3Sthurlow  * These are the vnode ops routines which implement the vnode interface to
1044bff34e3Sthurlow  * the networked file system.  These routines just take their parameters,
1054bff34e3Sthurlow  * make them look networkish by putting the right info into interface structs,
1064bff34e3Sthurlow  * and then calling the appropriate remote routine(s) to do the work.
1074bff34e3Sthurlow  *
1084bff34e3Sthurlow  * Note on directory name lookup cacheing:  If we detect a stale fhandle,
1094bff34e3Sthurlow  * we purge the directory cache relative to that vnode.  This way, the
1104bff34e3Sthurlow  * user won't get burned by the cache repeatedly.  See <smbfs/smbnode.h> for
1114bff34e3Sthurlow  * more details on smbnode locking.
1124bff34e3Sthurlow  */
1134bff34e3Sthurlow 
1144bff34e3Sthurlow static int	smbfs_open(vnode_t **, int, cred_t *, caller_context_t *);
1154bff34e3Sthurlow static int	smbfs_close(vnode_t *, int, int, offset_t, cred_t *,
1164bff34e3Sthurlow 			caller_context_t *);
1174bff34e3Sthurlow static int	smbfs_read(vnode_t *, struct uio *, int, cred_t *,
1184bff34e3Sthurlow 			caller_context_t *);
1194bff34e3Sthurlow static int	smbfs_write(vnode_t *, struct uio *, int, cred_t *,
1204bff34e3Sthurlow 			caller_context_t *);
121*7568150aSgwr static int	smbfs_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *,
122*7568150aSgwr 			caller_context_t *);
1234bff34e3Sthurlow static int	smbfs_getattr(vnode_t *, struct vattr *, int, cred_t *,
1244bff34e3Sthurlow 			caller_context_t *);
1254bff34e3Sthurlow static int	smbfs_setattr(vnode_t *, struct vattr *, int, cred_t *,
1264bff34e3Sthurlow 			caller_context_t *);
1274bff34e3Sthurlow static int	smbfs_access(vnode_t *, int, int, cred_t *, caller_context_t *);
1284bff34e3Sthurlow static int	smbfs_fsync(vnode_t *, int, cred_t *, caller_context_t *);
1294bff34e3Sthurlow static void	smbfs_inactive(vnode_t *, cred_t *, caller_context_t *);
1304bff34e3Sthurlow static int	smbfs_lookup(vnode_t *, char *, vnode_t **, struct pathname *,
1314bff34e3Sthurlow 			int, vnode_t *, cred_t *, caller_context_t *,
1324bff34e3Sthurlow 			int *, pathname_t *);
1334bff34e3Sthurlow static int	smbfs_create(vnode_t *, char *, struct vattr *, enum vcexcl,
1344bff34e3Sthurlow 			int, vnode_t **, cred_t *, int, caller_context_t *,
1354bff34e3Sthurlow 			vsecattr_t *);
1364bff34e3Sthurlow static int	smbfs_remove(vnode_t *, char *, cred_t *, caller_context_t *,
1374bff34e3Sthurlow 			int);
1384bff34e3Sthurlow static int	smbfs_rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
1394bff34e3Sthurlow 			caller_context_t *, int);
1404bff34e3Sthurlow static int	smbfs_mkdir(vnode_t *, char *, struct vattr *, vnode_t **,
1414bff34e3Sthurlow 			cred_t *, caller_context_t *, int, vsecattr_t *);
1424bff34e3Sthurlow static int	smbfs_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
1434bff34e3Sthurlow 			caller_context_t *, int);
1444bff34e3Sthurlow static int	smbfs_readdir(vnode_t *, struct uio *, cred_t *, int *,
1454bff34e3Sthurlow 			caller_context_t *, int);
1464bff34e3Sthurlow static int	smbfs_rwlock(vnode_t *, int, caller_context_t *);
1474bff34e3Sthurlow static void	smbfs_rwunlock(vnode_t *, int, caller_context_t *);
1484bff34e3Sthurlow static int	smbfs_seek(vnode_t *, offset_t, offset_t *, caller_context_t *);
1494bff34e3Sthurlow static int	smbfs_frlock(vnode_t *, int, struct flock64 *, int, offset_t,
1504bff34e3Sthurlow 			struct flk_callback *, cred_t *, caller_context_t *);
1514bff34e3Sthurlow static int	smbfs_space(vnode_t *, int, struct flock64 *, int, offset_t,
1524bff34e3Sthurlow 			cred_t *, caller_context_t *);
1534bff34e3Sthurlow static int	smbfs_pathconf(vnode_t *, int, ulong_t *, cred_t *,
1544bff34e3Sthurlow 			caller_context_t *);
155*7568150aSgwr static int	smbfs_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
156*7568150aSgwr 			caller_context_t *);
157*7568150aSgwr static int	smbfs_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
158*7568150aSgwr 			caller_context_t *);
1594bff34e3Sthurlow static int	smbfs_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *,
1604bff34e3Sthurlow 			caller_context_t *);
1614bff34e3Sthurlow 
1624bff34e3Sthurlow /* Dummy function to use until correct function is ported in */
1634bff34e3Sthurlow int noop_vnodeop() {
1644bff34e3Sthurlow 	return (0);
1654bff34e3Sthurlow }
1664bff34e3Sthurlow 
1674bff34e3Sthurlow struct vnodeops *smbfs_vnodeops = NULL;
1684bff34e3Sthurlow 
1694bff34e3Sthurlow /*
1704bff34e3Sthurlow  * Most unimplemented ops will return ENOSYS because of fs_nosys().
1714bff34e3Sthurlow  * The only ops where that won't work are ACCESS (due to open(2)
172*7568150aSgwr  * failures) and ... (anything else left?)
1734bff34e3Sthurlow  */
1744bff34e3Sthurlow const fs_operation_def_t smbfs_vnodeops_template[] = {
175*7568150aSgwr 	{ VOPNAME_OPEN,		{ .vop_open = smbfs_open } },
176*7568150aSgwr 	{ VOPNAME_CLOSE,	{ .vop_close = smbfs_close } },
177*7568150aSgwr 	{ VOPNAME_READ,		{ .vop_read = smbfs_read } },
178*7568150aSgwr 	{ VOPNAME_WRITE,	{ .vop_write = smbfs_write } },
179*7568150aSgwr 	{ VOPNAME_IOCTL,	{ .vop_ioctl = smbfs_ioctl } },
180*7568150aSgwr 	{ VOPNAME_GETATTR,	{ .vop_getattr = smbfs_getattr } },
181*7568150aSgwr 	{ VOPNAME_SETATTR,	{ .vop_setattr = smbfs_setattr } },
182*7568150aSgwr 	{ VOPNAME_ACCESS,	{ .vop_access = smbfs_access } },
183*7568150aSgwr 	{ VOPNAME_LOOKUP,	{ .vop_lookup = smbfs_lookup } },
184*7568150aSgwr 	{ VOPNAME_CREATE,	{ .vop_create = smbfs_create } },
185*7568150aSgwr 	{ VOPNAME_REMOVE,	{ .vop_remove = smbfs_remove } },
186*7568150aSgwr 	{ VOPNAME_LINK,		{ .error = fs_nosys } }, /* smbfs_link, */
187*7568150aSgwr 	{ VOPNAME_RENAME,	{ .vop_rename = smbfs_rename } },
188*7568150aSgwr 	{ VOPNAME_MKDIR,	{ .vop_mkdir = smbfs_mkdir } },
189*7568150aSgwr 	{ VOPNAME_RMDIR,	{ .vop_rmdir = smbfs_rmdir } },
190*7568150aSgwr 	{ VOPNAME_READDIR,	{ .vop_readdir = smbfs_readdir } },
191*7568150aSgwr 	{ VOPNAME_SYMLINK,	{ .error = fs_nosys } }, /* smbfs_symlink, */
192*7568150aSgwr 	{ VOPNAME_READLINK,	{ .error = fs_nosys } }, /* smbfs_readlink, */
193*7568150aSgwr 	{ VOPNAME_FSYNC,	{ .vop_fsync = smbfs_fsync } },
194*7568150aSgwr 	{ VOPNAME_INACTIVE,	{ .vop_inactive = smbfs_inactive } },
195*7568150aSgwr 	{ VOPNAME_FID,		{ .error = fs_nosys } }, /* smbfs_fid, */
196*7568150aSgwr 	{ VOPNAME_RWLOCK,	{ .vop_rwlock = smbfs_rwlock } },
197*7568150aSgwr 	{ VOPNAME_RWUNLOCK,	{ .vop_rwunlock = smbfs_rwunlock } },
198*7568150aSgwr 	{ VOPNAME_SEEK,		{ .vop_seek = smbfs_seek } },
199*7568150aSgwr 	{ VOPNAME_FRLOCK,	{ .vop_frlock = smbfs_frlock } },
200*7568150aSgwr 	{ VOPNAME_SPACE,	{ .vop_space = smbfs_space } },
201*7568150aSgwr 	{ VOPNAME_REALVP,	{ .error = fs_nosys } }, /* smbfs_realvp, */
202*7568150aSgwr 	{ VOPNAME_GETPAGE,	{ .error = fs_nosys } }, /* smbfs_getpage, */
203*7568150aSgwr 	{ VOPNAME_PUTPAGE,	{ .error = fs_nosys } }, /* smbfs_putpage, */
204*7568150aSgwr 	{ VOPNAME_MAP,		{ .error = fs_nosys } }, /* smbfs_map, */
205*7568150aSgwr 	{ VOPNAME_ADDMAP,	{ .error = fs_nosys } }, /* smbfs_addmap, */
206*7568150aSgwr 	{ VOPNAME_DELMAP,	{ .error = fs_nosys } }, /* smbfs_delmap, */
207*7568150aSgwr 	{ VOPNAME_DUMP,		{ .error = fs_nosys } }, /* smbfs_dump, */
208*7568150aSgwr 	{ VOPNAME_PATHCONF,	{ .vop_pathconf = smbfs_pathconf } },
209*7568150aSgwr 	{ VOPNAME_PAGEIO,	{ .error = fs_nosys } }, /* smbfs_pageio, */
210*7568150aSgwr 	{ VOPNAME_SETSECATTR,	{ .vop_setsecattr = smbfs_setsecattr } },
211*7568150aSgwr 	{ VOPNAME_GETSECATTR,	{ .vop_getsecattr = smbfs_getsecattr } },
212*7568150aSgwr 	{ VOPNAME_SHRLOCK,	{ .vop_shrlock = smbfs_shrlock } },
2134bff34e3Sthurlow 	{ NULL, NULL }
2144bff34e3Sthurlow };
2154bff34e3Sthurlow 
2164bff34e3Sthurlow /*
2174bff34e3Sthurlow  * XXX
2184bff34e3Sthurlow  * When new and relevant functionality is enabled, we should be
2194bff34e3Sthurlow  * calling vfs_set_feature() to inform callers that pieces of
2204bff34e3Sthurlow  * functionality are available, per PSARC 2007/227, e.g.
2214bff34e3Sthurlow  *
2224bff34e3Sthurlow  * VFSFT_XVATTR            Supports xvattr for attrs
2234bff34e3Sthurlow  * VFSFT_CASEINSENSITIVE   Supports case-insensitive
2244bff34e3Sthurlow  * VFSFT_NOCASESENSITIVE   NOT case-sensitive
2254bff34e3Sthurlow  * VFSFT_DIRENTFLAGS       Supports dirent flags
2264bff34e3Sthurlow  * VFSFT_ACLONCREATE       Supports ACL on create
2274bff34e3Sthurlow  * VFSFT_ACEMASKONACCESS   Can use ACEMASK for access
2284bff34e3Sthurlow  */
2294bff34e3Sthurlow /* ARGSUSED */
2304bff34e3Sthurlow static int
2314bff34e3Sthurlow smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
2324bff34e3Sthurlow {
2334bff34e3Sthurlow 	struct vattr	va;
2344bff34e3Sthurlow 	smbnode_t	*np;
2354bff34e3Sthurlow 	vnode_t		*vp;
2364bff34e3Sthurlow 	u_int32_t	rights, rightsrcvd;
2374bff34e3Sthurlow 	u_int16_t	fid, oldfid;
2384bff34e3Sthurlow 	struct smb_cred scred;
2394bff34e3Sthurlow 	smbmntinfo_t	*smi;
2404bff34e3Sthurlow 	cred_t		*oldcr;
2414bff34e3Sthurlow 	int		attrcacheupdated = 0;
2424bff34e3Sthurlow 	int		tmperror;
2434bff34e3Sthurlow 	int		error = 0;
2444bff34e3Sthurlow 
2454bff34e3Sthurlow 	vp = *vpp;
2464bff34e3Sthurlow 	np = VTOSMB(vp);
2474bff34e3Sthurlow 	smi = VTOSMI(vp);
2484bff34e3Sthurlow 
2494bff34e3Sthurlow 	if (curproc->p_zone != smi->smi_zone)
2504bff34e3Sthurlow 		return (EIO);
2514bff34e3Sthurlow 
2524bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2534bff34e3Sthurlow 		return (EIO);
2544bff34e3Sthurlow 
2554bff34e3Sthurlow 	if (vp->v_type != VREG && vp->v_type != VDIR) { /* XXX VLNK? */
2564bff34e3Sthurlow 		SMBVDEBUG("open eacces vtype=%d\n", vp->v_type);
2574bff34e3Sthurlow 		return (EACCES);
2584bff34e3Sthurlow 	}
2594bff34e3Sthurlow 
2604bff34e3Sthurlow 	/*
2614bff34e3Sthurlow 	 * Get exclusive access to n_fid and related stuff.
2624bff34e3Sthurlow 	 * No returns after this until out.
2634bff34e3Sthurlow 	 */
2644bff34e3Sthurlow 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp)))
2654bff34e3Sthurlow 		return (EINTR);
2664bff34e3Sthurlow 	smb_credinit(&scred, curproc, cr);
2674bff34e3Sthurlow 
2684bff34e3Sthurlow 	/*
2694bff34e3Sthurlow 	 * Directory open is easy.
2704bff34e3Sthurlow 	 */
2714bff34e3Sthurlow 	if (vp->v_type == VDIR) {
2724bff34e3Sthurlow 		np->n_dirrefs++;
2734bff34e3Sthurlow 		goto have_fid;
2744bff34e3Sthurlow 	}
2754bff34e3Sthurlow 
2764bff34e3Sthurlow 	/*
2774bff34e3Sthurlow 	 * If caller specified O_TRUNC/FTRUNC, then be sure to set
2784bff34e3Sthurlow 	 * FWRITE (to drive successful setattr(size=0) after open)
2794bff34e3Sthurlow 	 */
2804bff34e3Sthurlow 	if (flag & FTRUNC)
2814bff34e3Sthurlow 		flag |= FWRITE;
2824bff34e3Sthurlow 
2834bff34e3Sthurlow 	/*
2844bff34e3Sthurlow 	 * If we already have it open, check to see if current rights
2854bff34e3Sthurlow 	 * are sufficient for this open.
2864bff34e3Sthurlow 	 */
2874bff34e3Sthurlow 	if (np->n_fidrefs) {
2884bff34e3Sthurlow 		int upgrade = 0;
2894bff34e3Sthurlow 
2904bff34e3Sthurlow 		/* BEGIN CSTYLED */
2914bff34e3Sthurlow 		if ((flag & FWRITE) &&
2924bff34e3Sthurlow 		    !(np->n_rights & (SA_RIGHT_FILE_WRITE_DATA |
2934bff34e3Sthurlow 				GENERIC_RIGHT_ALL_ACCESS |
2944bff34e3Sthurlow 				GENERIC_RIGHT_WRITE_ACCESS)))
2954bff34e3Sthurlow 			upgrade = 1;
2964bff34e3Sthurlow 		if ((flag & FREAD) &&
2974bff34e3Sthurlow 		    !(np->n_rights & (SA_RIGHT_FILE_READ_DATA |
2984bff34e3Sthurlow 				GENERIC_RIGHT_ALL_ACCESS |
2994bff34e3Sthurlow 				GENERIC_RIGHT_READ_ACCESS)))
3004bff34e3Sthurlow 			upgrade = 1;
3014bff34e3Sthurlow 		/* END CSTYLED */
3024bff34e3Sthurlow 		if (!upgrade) {
3034bff34e3Sthurlow 			/*
3044bff34e3Sthurlow 			 *  the existing open is good enough
3054bff34e3Sthurlow 			 */
3064bff34e3Sthurlow 			np->n_fidrefs++;
3074bff34e3Sthurlow 			goto have_fid;
3084bff34e3Sthurlow 		}
3094bff34e3Sthurlow 	}
3104bff34e3Sthurlow 	rights = np->n_fidrefs ? np->n_rights : 0;
3114bff34e3Sthurlow 
3124bff34e3Sthurlow 	/*
3134bff34e3Sthurlow 	 * we always ask for READ_CONTROL so we can always get the
3144bff34e3Sthurlow 	 * owner/group IDs to satisfy a stat.
3154bff34e3Sthurlow 	 * XXX: verify that works with "drop boxes"
3164bff34e3Sthurlow 	 */
3174bff34e3Sthurlow 	rights |= STD_RIGHT_READ_CONTROL_ACCESS;
3184bff34e3Sthurlow 	if ((flag & FREAD))
3194bff34e3Sthurlow 		rights |= SA_RIGHT_FILE_READ_DATA;
3204bff34e3Sthurlow 	if ((flag & FWRITE))
3214bff34e3Sthurlow 		rights |= SA_RIGHT_FILE_APPEND_DATA | SA_RIGHT_FILE_WRITE_DATA;
3224bff34e3Sthurlow 
3234bff34e3Sthurlow 	/* XXX: open gets the current size, but we don't use it. */
3244bff34e3Sthurlow 	error = smbfs_smb_open(np, rights, &scred, &attrcacheupdated, &fid,
3254bff34e3Sthurlow 	    NULL, 0, 0, NULL, &rightsrcvd);
3264bff34e3Sthurlow 	if (error)
3274bff34e3Sthurlow 		goto out;
3284bff34e3Sthurlow 
3294bff34e3Sthurlow 	/*
3304bff34e3Sthurlow 	 * We have a new FID and access rights.
3314bff34e3Sthurlow 	 */
3324bff34e3Sthurlow 	oldfid = np->n_fid;
3334bff34e3Sthurlow 	np->n_fid = fid;
3344bff34e3Sthurlow 	np->n_rights = rightsrcvd;
3354bff34e3Sthurlow 	np->n_fidrefs++;
3364bff34e3Sthurlow 	if (np->n_fidrefs > 1) {
3374bff34e3Sthurlow 		/*
3384bff34e3Sthurlow 		 * We already had it open (presumably because
3394bff34e3Sthurlow 		 * it was open with insufficient rights.)
3404bff34e3Sthurlow 		 * Close old wire-open.
3414bff34e3Sthurlow 		 */
3424bff34e3Sthurlow 		tmperror = smbfs_smb_close(smi->smi_share,
3434bff34e3Sthurlow 		    oldfid, &np->n_mtime, &scred);
3444bff34e3Sthurlow 		if (tmperror)
3454bff34e3Sthurlow 			SMBVDEBUG("error %d closing %s\n",
3464bff34e3Sthurlow 			    tmperror, np->n_rpath);
3474bff34e3Sthurlow 	}
3484bff34e3Sthurlow 
3494bff34e3Sthurlow 	/*
3504bff34e3Sthurlow 	 * This thread did the open.
3514bff34e3Sthurlow 	 * Save our credentials too.
3524bff34e3Sthurlow 	 */
3534bff34e3Sthurlow 	mutex_enter(&np->r_statelock);
3544bff34e3Sthurlow 	oldcr = np->r_cred;
3554bff34e3Sthurlow 	np->r_cred = cr;
3564bff34e3Sthurlow 	crhold(cr);
3574bff34e3Sthurlow 	if (oldcr)
3584bff34e3Sthurlow 		crfree(oldcr);
3594bff34e3Sthurlow 	mutex_exit(&np->r_statelock);
3604bff34e3Sthurlow 
3614bff34e3Sthurlow have_fid:
3624bff34e3Sthurlow 	/* Get attributes (maybe). */
3634bff34e3Sthurlow 
3644bff34e3Sthurlow 
3654bff34e3Sthurlow 	/* Darwin (derived) code. */
3664bff34e3Sthurlow 
3674bff34e3Sthurlow 	va.va_mask = AT_MTIME;
3684bff34e3Sthurlow 	if (np->n_flag & NMODIFIED)
3694bff34e3Sthurlow 		smbfs_attr_cacheremove(np);
3704bff34e3Sthurlow 
3714bff34e3Sthurlow 	/*
3724bff34e3Sthurlow 	 * Try to get attributes, but don't bail on error.
3734bff34e3Sthurlow 	 * We already hold r_lkserlock/reader so note:
3744bff34e3Sthurlow 	 * this call will recursively take r_lkserlock.
3754bff34e3Sthurlow 	 */
3764bff34e3Sthurlow 	tmperror = smbfsgetattr(vp, &va, cr);
3774bff34e3Sthurlow 	if (tmperror)
3784bff34e3Sthurlow 		SMBERROR("getattr failed, error=%d", tmperror);
3794bff34e3Sthurlow 	else
3804bff34e3Sthurlow 		np->n_mtime.tv_sec = va.va_mtime.tv_sec;
3814bff34e3Sthurlow 
3824bff34e3Sthurlow out:
3834bff34e3Sthurlow 	smb_credrele(&scred);
3844bff34e3Sthurlow 	smbfs_rw_exit(&np->r_lkserlock);
3854bff34e3Sthurlow 	return (error);
3864bff34e3Sthurlow }
3874bff34e3Sthurlow 
3884bff34e3Sthurlow /*ARGSUSED*/
3894bff34e3Sthurlow static int
3904bff34e3Sthurlow smbfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
3914bff34e3Sthurlow 	caller_context_t *ct)
3924bff34e3Sthurlow {
3934bff34e3Sthurlow 	smbnode_t	*np;
3944bff34e3Sthurlow 	int		error = 0;
3954bff34e3Sthurlow 	struct smb_cred scred;
3964bff34e3Sthurlow 
3974bff34e3Sthurlow 	np = VTOSMB(vp);
3984bff34e3Sthurlow 
3994bff34e3Sthurlow 	/*
4004bff34e3Sthurlow 	 * Don't "bail out" for VFS_UNMOUNTED here,
4014bff34e3Sthurlow 	 * as we want to do cleanup, etc.
4024bff34e3Sthurlow 	 */
4034bff34e3Sthurlow 
4044bff34e3Sthurlow 	/*
4054bff34e3Sthurlow 	 * zone_enter(2) prevents processes from changing zones with SMBFS files
4064bff34e3Sthurlow 	 * open; if we happen to get here from the wrong zone we can't do
4074bff34e3Sthurlow 	 * anything over the wire.
4084bff34e3Sthurlow 	 */
4094bff34e3Sthurlow 	if (VTOSMI(vp)->smi_zone != curproc->p_zone) {
4104bff34e3Sthurlow 		/*
4114bff34e3Sthurlow 		 * We could attempt to clean up locks, except we're sure
4124bff34e3Sthurlow 		 * that the current process didn't acquire any locks on
4134bff34e3Sthurlow 		 * the file: any attempt to lock a file belong to another zone
4144bff34e3Sthurlow 		 * will fail, and one can't lock an SMBFS file and then change
4154bff34e3Sthurlow 		 * zones, as that fails too.
4164bff34e3Sthurlow 		 *
4174bff34e3Sthurlow 		 * Returning an error here is the sane thing to do.  A
4184bff34e3Sthurlow 		 * subsequent call to VN_RELE() which translates to a
4194bff34e3Sthurlow 		 * smbfs_inactive() will clean up state: if the zone of the
4204bff34e3Sthurlow 		 * vnode's origin is still alive and kicking, an async worker
4214bff34e3Sthurlow 		 * thread will handle the request (from the correct zone), and
4224bff34e3Sthurlow 		 * everything (minus the final smbfs_getattr_otw() call) should
4234bff34e3Sthurlow 		 * be OK. If the zone is going away smbfs_async_inactive() will
4244bff34e3Sthurlow 		 * throw away cached pages inline.
4254bff34e3Sthurlow 		 */
4264bff34e3Sthurlow 		return (EIO);
4274bff34e3Sthurlow 	}
4284bff34e3Sthurlow 
4294bff34e3Sthurlow 	/*
4304bff34e3Sthurlow 	 * If we are using local locking for this filesystem, then
4314bff34e3Sthurlow 	 * release all of the SYSV style record locks.  Otherwise,
4324bff34e3Sthurlow 	 * we are doing network locking and we need to release all
4334bff34e3Sthurlow 	 * of the network locks.  All of the locks held by this
4344bff34e3Sthurlow 	 * process on this file are released no matter what the
4354bff34e3Sthurlow 	 * incoming reference count is.
4364bff34e3Sthurlow 	 */
4374bff34e3Sthurlow 	if (VTOSMI(vp)->smi_flags & SMI_LLOCK) {
4384bff34e3Sthurlow 		cleanlocks(vp, ttoproc(curthread)->p_pid, 0);
4394bff34e3Sthurlow 		cleanshares(vp, ttoproc(curthread)->p_pid);
4404bff34e3Sthurlow 	}
4414bff34e3Sthurlow 
4424bff34e3Sthurlow 	if (count > 1)
4434bff34e3Sthurlow 		return (0);
4444bff34e3Sthurlow 	/*
4454bff34e3Sthurlow 	 * OK, do "last close" stuff.
4464bff34e3Sthurlow 	 */
4474bff34e3Sthurlow 
4484bff34e3Sthurlow 
4494bff34e3Sthurlow 	/*
4504bff34e3Sthurlow 	 * Do the CIFS close.
4514bff34e3Sthurlow 	 * Darwin code
4524bff34e3Sthurlow 	 */
4534bff34e3Sthurlow 
4544bff34e3Sthurlow 	/*
4554bff34e3Sthurlow 	 * Exclusive lock for modifying n_fid stuff.
4564bff34e3Sthurlow 	 * Don't want this one ever interruptible.
4574bff34e3Sthurlow 	 */
4584bff34e3Sthurlow 	(void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
4594bff34e3Sthurlow 	smb_credinit(&scred, curproc, cr);
4604bff34e3Sthurlow 
4614bff34e3Sthurlow 	error = 0;
4624bff34e3Sthurlow 	if (vp->v_type == VDIR) {
4634bff34e3Sthurlow 		struct smbfs_fctx *fctx;
4644bff34e3Sthurlow 		ASSERT(np->n_dirrefs > 0);
4654bff34e3Sthurlow 		if (--np->n_dirrefs)
4664bff34e3Sthurlow 			goto out;
4674bff34e3Sthurlow 		if ((fctx = np->n_dirseq) != NULL) {
4684bff34e3Sthurlow 			np->n_dirseq = NULL;
4694bff34e3Sthurlow 			error = smbfs_smb_findclose(fctx, &scred);
4704bff34e3Sthurlow 		}
4714bff34e3Sthurlow 	} else {
4724bff34e3Sthurlow 		uint16_t ofid;
4734bff34e3Sthurlow 		ASSERT(np->n_fidrefs > 0);
4744bff34e3Sthurlow 		if (--np->n_fidrefs)
4754bff34e3Sthurlow 			goto out;
4764bff34e3Sthurlow 		if ((ofid = np->n_fid) != SMB_FID_UNUSED) {
4774bff34e3Sthurlow 			np->n_fid = SMB_FID_UNUSED;
4784bff34e3Sthurlow 			error = smbfs_smb_close(np->n_mount->smi_share,
4794bff34e3Sthurlow 			    ofid, NULL, &scred);
4804bff34e3Sthurlow 		}
4814bff34e3Sthurlow 	}
4824bff34e3Sthurlow 	if (error) {
4834bff34e3Sthurlow 		SMBERROR("error %d closing %s\n",
4844bff34e3Sthurlow 		    error, np->n_rpath);
4854bff34e3Sthurlow 	}
4864bff34e3Sthurlow 
4874bff34e3Sthurlow 	if (np->n_flag & NATTRCHANGED)
4884bff34e3Sthurlow 		smbfs_attr_cacheremove(np);
4894bff34e3Sthurlow 
4904bff34e3Sthurlow out:
4914bff34e3Sthurlow 	smb_credrele(&scred);
4924bff34e3Sthurlow 	smbfs_rw_exit(&np->r_lkserlock);
4934bff34e3Sthurlow 
4944bff34e3Sthurlow 	/* don't return any errors */
4954bff34e3Sthurlow 	return (0);
4964bff34e3Sthurlow }
4974bff34e3Sthurlow 
4984bff34e3Sthurlow /* ARGSUSED */
4994bff34e3Sthurlow static int
5004bff34e3Sthurlow smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
5014bff34e3Sthurlow 	caller_context_t *ct)
5024bff34e3Sthurlow {
5034bff34e3Sthurlow 	int		error;
5044bff34e3Sthurlow 	struct vattr	va;
5054bff34e3Sthurlow 	smbmntinfo_t	*smi;
5064bff34e3Sthurlow 	smbnode_t	*np;
5074bff34e3Sthurlow 	/* u_offset_t	off; */
5084bff34e3Sthurlow 	/* offset_t	diff; */
5094bff34e3Sthurlow 
5104bff34e3Sthurlow 	np = VTOSMB(vp);
5114bff34e3Sthurlow 	smi = VTOSMI(vp);
5124bff34e3Sthurlow 
5134bff34e3Sthurlow 	if (curproc->p_zone != smi->smi_zone)
5144bff34e3Sthurlow 		return (EIO);
5154bff34e3Sthurlow 
5164bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
5174bff34e3Sthurlow 		return (EIO);
5184bff34e3Sthurlow 
5194bff34e3Sthurlow 	ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER));
5204bff34e3Sthurlow 
5214bff34e3Sthurlow 	if (vp->v_type != VREG)
5224bff34e3Sthurlow 		return (EISDIR);
5234bff34e3Sthurlow 
5244bff34e3Sthurlow 	if (uiop->uio_resid == 0)
5254bff34e3Sthurlow 		return (0);
5264bff34e3Sthurlow 
5274bff34e3Sthurlow 	/*
5284bff34e3Sthurlow 	 * Like NFS3, just check for 63-bit overflow.
5294bff34e3Sthurlow 	 * Our SMB layer takes care to return EFBIG
5304bff34e3Sthurlow 	 * when it has to fallback to a 32-bit call.
5314bff34e3Sthurlow 	 */
5324bff34e3Sthurlow 	if (uiop->uio_loffset < 0 ||
5334bff34e3Sthurlow 	    uiop->uio_loffset + uiop->uio_resid < 0)
5344bff34e3Sthurlow 		return (EINVAL);
5354bff34e3Sthurlow 
5364bff34e3Sthurlow 	/* Shared lock for n_fid use in smbfs_readvnode */
5374bff34e3Sthurlow 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
5384bff34e3Sthurlow 		return (EINTR);
5394bff34e3Sthurlow 
5404bff34e3Sthurlow 	/* get vnode attributes from server */
5414bff34e3Sthurlow 	va.va_mask = AT_SIZE | AT_MTIME;
5424bff34e3Sthurlow 	if (error = smbfsgetattr(vp, &va, cr))
5434bff34e3Sthurlow 		goto out;
5444bff34e3Sthurlow 
5454bff34e3Sthurlow 	/* should probably update mtime with mtime from server here */
5464bff34e3Sthurlow 
5474bff34e3Sthurlow 	/*
5484bff34e3Sthurlow 	 * Darwin had a loop here that handled paging stuff.
5494bff34e3Sthurlow 	 * Solaris does paging differently, so no loop needed.
5504bff34e3Sthurlow 	 */
5514bff34e3Sthurlow 	error = smbfs_readvnode(vp, uiop, cr, &va);
5524bff34e3Sthurlow 
5534bff34e3Sthurlow out:
5544bff34e3Sthurlow 	smbfs_rw_exit(&np->r_lkserlock);
5554bff34e3Sthurlow 	return (error);
5564bff34e3Sthurlow 
5574bff34e3Sthurlow }
5584bff34e3Sthurlow 
5594bff34e3Sthurlow 
5604bff34e3Sthurlow /* ARGSUSED */
5614bff34e3Sthurlow static int
5624bff34e3Sthurlow smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
5634bff34e3Sthurlow 	caller_context_t *ct)
5644bff34e3Sthurlow {
5654bff34e3Sthurlow 	int		error;
5664bff34e3Sthurlow 	smbmntinfo_t 	*smi;
5674bff34e3Sthurlow 	smbnode_t 	*np;
5684bff34e3Sthurlow 	int		timo = SMBWRTTIMO;
5694bff34e3Sthurlow 
5704bff34e3Sthurlow 	np = VTOSMB(vp);
5714bff34e3Sthurlow 	smi = VTOSMI(vp);
5724bff34e3Sthurlow 
5734bff34e3Sthurlow 	if (curproc->p_zone != smi->smi_zone)
5744bff34e3Sthurlow 		return (EIO);
5754bff34e3Sthurlow 
5764bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
5774bff34e3Sthurlow 		return (EIO);
5784bff34e3Sthurlow 
5794bff34e3Sthurlow 	ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_WRITER));
5804bff34e3Sthurlow 
5814bff34e3Sthurlow 	if (vp->v_type != VREG)
5824bff34e3Sthurlow 		return (EISDIR);
5834bff34e3Sthurlow 
5844bff34e3Sthurlow 	if (uiop->uio_resid == 0)
5854bff34e3Sthurlow 		return (0);
5864bff34e3Sthurlow 
5874bff34e3Sthurlow 	/* Shared lock for n_fid use in smbfs_writevnode */
5884bff34e3Sthurlow 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
5894bff34e3Sthurlow 		return (EINTR);
5904bff34e3Sthurlow 
5914bff34e3Sthurlow 
5924bff34e3Sthurlow 	/*
5934bff34e3Sthurlow 	 * Darwin had a loop here that handled paging stuff.
5944bff34e3Sthurlow 	 * Solaris does paging differently, so no loop needed.
5954bff34e3Sthurlow 	 */
5964bff34e3Sthurlow 	error = smbfs_writevnode(vp, uiop, cr, ioflag, timo);
5974bff34e3Sthurlow 
5984bff34e3Sthurlow 	smbfs_rw_exit(&np->r_lkserlock);
5994bff34e3Sthurlow 	return (error);
6004bff34e3Sthurlow 
6014bff34e3Sthurlow }
6024bff34e3Sthurlow 
6034bff34e3Sthurlow 
604*7568150aSgwr /* ARGSUSED */
605*7568150aSgwr static int
606*7568150aSgwr smbfs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag,
607*7568150aSgwr 	cred_t *cr, int *rvalp,	caller_context_t *ct)
608*7568150aSgwr {
609*7568150aSgwr 	int		error;
610*7568150aSgwr 	smbmntinfo_t 	*smi;
611*7568150aSgwr 
612*7568150aSgwr 	smi = VTOSMI(vp);
613*7568150aSgwr 
614*7568150aSgwr 	if (curproc->p_zone != smi->smi_zone)
615*7568150aSgwr 		return (EIO);
616*7568150aSgwr 
617*7568150aSgwr 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
618*7568150aSgwr 		return (EIO);
619*7568150aSgwr 
620*7568150aSgwr 	switch (cmd) {
621*7568150aSgwr 		/* First three from ZFS. XXX - need these? */
622*7568150aSgwr 
623*7568150aSgwr 	case _FIOFFS:
624*7568150aSgwr 		error = smbfs_fsync(vp, 0, cr, ct);
625*7568150aSgwr 		break;
626*7568150aSgwr 
627*7568150aSgwr 		/*
628*7568150aSgwr 		 * The following two ioctls are used by bfu.
629*7568150aSgwr 		 * Silently ignore to avoid bfu errors.
630*7568150aSgwr 		 */
631*7568150aSgwr 	case _FIOGDIO:
632*7568150aSgwr 	case _FIOSDIO:
633*7568150aSgwr 		error = 0;
634*7568150aSgwr 		break;
635*7568150aSgwr 
636*7568150aSgwr #ifdef NOT_YET	/* XXX - from the NFS code. */
637*7568150aSgwr 	case _FIODIRECTIO:
638*7568150aSgwr 		error = smbfs_directio(vp, (int)arg, cr);
639*7568150aSgwr #endif
640*7568150aSgwr 
641*7568150aSgwr 		/*
642*7568150aSgwr 		 * Allow get/set with "raw" security descriptor (SD) data.
643*7568150aSgwr 		 * Useful for testing, diagnosing idmap problems, etc.
644*7568150aSgwr 		 */
645*7568150aSgwr 	case SMBFSIO_GETSD:
646*7568150aSgwr 		error = smbfs_ioc_getsd(vp, arg, flag, cr);
647*7568150aSgwr 		break;
648*7568150aSgwr 
649*7568150aSgwr 	case SMBFSIO_SETSD:
650*7568150aSgwr 		error = smbfs_ioc_setsd(vp, arg, flag, cr);
651*7568150aSgwr 		break;
652*7568150aSgwr 
653*7568150aSgwr 	default:
654*7568150aSgwr 		error = ENOTTY;
655*7568150aSgwr 		break;
656*7568150aSgwr 	}
657*7568150aSgwr 
658*7568150aSgwr 	return (error);
659*7568150aSgwr }
660*7568150aSgwr 
661*7568150aSgwr 
6624bff34e3Sthurlow /*
6634bff34e3Sthurlow  * Return either cached or remote attributes. If get remote attr
6644bff34e3Sthurlow  * use them to check and invalidate caches, then cache the new attributes.
6654bff34e3Sthurlow  *
6664bff34e3Sthurlow  * XXX
6674bff34e3Sthurlow  * This op should eventually support PSARC 2007/315, Extensible Attribute
6684bff34e3Sthurlow  * Interfaces, for richer metadata.
6694bff34e3Sthurlow  */
6704bff34e3Sthurlow /* ARGSUSED */
6714bff34e3Sthurlow static int
6724bff34e3Sthurlow smbfs_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
6734bff34e3Sthurlow 	caller_context_t *ct)
6744bff34e3Sthurlow {
6754bff34e3Sthurlow 	smbnode_t *np;
6764bff34e3Sthurlow 	smbmntinfo_t *smi;
6774bff34e3Sthurlow 
6784bff34e3Sthurlow 	smi = VTOSMI(vp);
6794bff34e3Sthurlow 
6804bff34e3Sthurlow 	if (curproc->p_zone != smi->smi_zone)
6814bff34e3Sthurlow 		return (EIO);
6824bff34e3Sthurlow 
6834bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
6844bff34e3Sthurlow 		return (EIO);
6854bff34e3Sthurlow 
6864bff34e3Sthurlow 	/*
6874bff34e3Sthurlow 	 * If it has been specified that the return value will
6884bff34e3Sthurlow 	 * just be used as a hint, and we are only being asked
6894bff34e3Sthurlow 	 * for size, fsid or rdevid, then return the client's
6904bff34e3Sthurlow 	 * notion of these values without checking to make sure
6914bff34e3Sthurlow 	 * that the attribute cache is up to date.
6924bff34e3Sthurlow 	 * The whole point is to avoid an over the wire GETATTR
6934bff34e3Sthurlow 	 * call.
6944bff34e3Sthurlow 	 */
6954bff34e3Sthurlow 	np = VTOSMB(vp);
6964bff34e3Sthurlow 	if (flags & ATTR_HINT) {
6974bff34e3Sthurlow 		if (vap->va_mask ==
6984bff34e3Sthurlow 		    (vap->va_mask & (AT_SIZE | AT_FSID | AT_RDEV))) {
6994bff34e3Sthurlow 			mutex_enter(&np->r_statelock);
7004bff34e3Sthurlow 			if (vap->va_mask | AT_SIZE)
7014bff34e3Sthurlow 				vap->va_size = np->r_size;
7024bff34e3Sthurlow 			if (vap->va_mask | AT_FSID)
7034bff34e3Sthurlow 				vap->va_fsid = np->r_attr.va_fsid;
7044bff34e3Sthurlow 			if (vap->va_mask | AT_RDEV)
7054bff34e3Sthurlow 				vap->va_rdev = np->r_attr.va_rdev;
7064bff34e3Sthurlow 			mutex_exit(&np->r_statelock);
7074bff34e3Sthurlow 			return (0);
7084bff34e3Sthurlow 		}
7094bff34e3Sthurlow 	}
7104bff34e3Sthurlow 
7114bff34e3Sthurlow 
7124bff34e3Sthurlow 	return (smbfsgetattr(vp, vap, cr));
7134bff34e3Sthurlow }
7144bff34e3Sthurlow 
7154bff34e3Sthurlow /*
7164bff34e3Sthurlow  * Mostly from Darwin smbfs_getattr()
7174bff34e3Sthurlow  */
7184bff34e3Sthurlow int
7194bff34e3Sthurlow smbfsgetattr(vnode_t *vp, struct vattr *vap, cred_t *cr)
7204bff34e3Sthurlow {
7214bff34e3Sthurlow 	int error;
7224bff34e3Sthurlow 	smbnode_t *np;
7234bff34e3Sthurlow 	struct smb_cred scred;
7244bff34e3Sthurlow 	struct smbfattr fattr;
7254bff34e3Sthurlow 
7264bff34e3Sthurlow 	ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone);
7274bff34e3Sthurlow 
7284bff34e3Sthurlow 	np = VTOSMB(vp);
7294bff34e3Sthurlow 
7304bff34e3Sthurlow 	/*
7314bff34e3Sthurlow 	 * If we've got cached attributes, we're done, otherwise go
7324bff34e3Sthurlow 	 * to the server to get attributes, which will update the cache
7334bff34e3Sthurlow 	 * in the process.
7344bff34e3Sthurlow 	 *
7354bff34e3Sthurlow 	 * This section from Darwin smbfs_getattr,
7364bff34e3Sthurlow 	 * but then modified a lot.
7374bff34e3Sthurlow 	 */
7384bff34e3Sthurlow 	error = smbfs_attr_cachelookup(vp, vap);
7394bff34e3Sthurlow 	if (error != ENOENT)
7404bff34e3Sthurlow 		return (error);
7414bff34e3Sthurlow 
7424bff34e3Sthurlow 	/* Shared lock for (possible) n_fid use. */
7434bff34e3Sthurlow 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
7444bff34e3Sthurlow 		return (EINTR);
7454bff34e3Sthurlow 	smb_credinit(&scred, curproc, cr);
7464bff34e3Sthurlow 
7474bff34e3Sthurlow 	error = smbfs_smb_getfattr(np, &fattr, &scred);
7484bff34e3Sthurlow 
7494bff34e3Sthurlow 	smb_credrele(&scred);
7504bff34e3Sthurlow 	smbfs_rw_exit(&np->r_lkserlock);
7514bff34e3Sthurlow 
7524bff34e3Sthurlow 	if (!error) {
7534bff34e3Sthurlow 		smbfs_attr_cacheenter(vp, &fattr);
7544bff34e3Sthurlow 		error = smbfs_attr_cachelookup(vp, vap);
7554bff34e3Sthurlow 	}
7564bff34e3Sthurlow 	return (error);
7574bff34e3Sthurlow }
7584bff34e3Sthurlow 
7594bff34e3Sthurlow /*
7604bff34e3Sthurlow  * XXX
7614bff34e3Sthurlow  * This op should eventually support PSARC 2007/315, Extensible Attribute
7624bff34e3Sthurlow  * Interfaces, for richer metadata.
7634bff34e3Sthurlow  */
7644bff34e3Sthurlow /*ARGSUSED4*/
7654bff34e3Sthurlow static int
7664bff34e3Sthurlow smbfs_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
7674bff34e3Sthurlow 		caller_context_t *ct)
7684bff34e3Sthurlow {
7694bff34e3Sthurlow 	int		error;
7704bff34e3Sthurlow 	uint_t		mask;
7714bff34e3Sthurlow 	struct vattr	oldva;
7724bff34e3Sthurlow 	smbmntinfo_t	*smi;
7734bff34e3Sthurlow 
7744bff34e3Sthurlow 	smi = VTOSMI(vp);
7754bff34e3Sthurlow 
7764bff34e3Sthurlow 	if (curproc->p_zone != smi->smi_zone)
7774bff34e3Sthurlow 		return (EIO);
7784bff34e3Sthurlow 
7794bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
7804bff34e3Sthurlow 		return (EIO);
7814bff34e3Sthurlow 
7824bff34e3Sthurlow 	mask = vap->va_mask;
7834bff34e3Sthurlow 	if (mask & AT_NOSET)
7844bff34e3Sthurlow 		return (EINVAL);
7854bff34e3Sthurlow 
7864bff34e3Sthurlow 	oldva.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
7874bff34e3Sthurlow 	error = smbfsgetattr(vp, &oldva, cr);
7884bff34e3Sthurlow 	if (error)
7894bff34e3Sthurlow 		return (error);
7904bff34e3Sthurlow 
7914bff34e3Sthurlow 	error = secpolicy_vnode_setattr(cr, vp, vap, &oldva, flags,
7924bff34e3Sthurlow 	    smbfs_accessx, vp);
7934bff34e3Sthurlow 	if (error)
7944bff34e3Sthurlow 		return (error);
7954bff34e3Sthurlow 
7964bff34e3Sthurlow 	return (smbfssetattr(vp, vap, flags, cr));
7974bff34e3Sthurlow }
7984bff34e3Sthurlow 
7994bff34e3Sthurlow /*
8004bff34e3Sthurlow  * Mostly from Darwin smbfs_setattr()
8014bff34e3Sthurlow  * but then modified a lot.
8024bff34e3Sthurlow  */
8034bff34e3Sthurlow /* ARGSUSED */
8044bff34e3Sthurlow static int
8054bff34e3Sthurlow smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
8064bff34e3Sthurlow {
8074bff34e3Sthurlow 	int		error = 0;
8084bff34e3Sthurlow 	smbnode_t	*np = VTOSMB(vp);
8094bff34e3Sthurlow 	smbmntinfo_t	*smi = VTOSMI(vp);
8104bff34e3Sthurlow 	uint_t		mask = vap->va_mask;
8114bff34e3Sthurlow 	struct timespec	*mtime, *atime;
8124bff34e3Sthurlow 	struct smb_cred	scred;
8134bff34e3Sthurlow 	int		cerror, modified = 0;
8144bff34e3Sthurlow 	unsigned short	fid;
8154bff34e3Sthurlow 	int have_fid = 0;
8164bff34e3Sthurlow 	uint32_t rights = 0;
8174bff34e3Sthurlow 
8184bff34e3Sthurlow 	ASSERT(curproc->p_zone == smi->smi_zone);
8194bff34e3Sthurlow 
8204bff34e3Sthurlow 	/*
8214bff34e3Sthurlow 	 * If our caller is trying to set multiple attributes, they
8224bff34e3Sthurlow 	 * can make no assumption about what order they are done in.
8234bff34e3Sthurlow 	 * Here we try to do them in order of decreasing likelihood
8244bff34e3Sthurlow 	 * of failure, just to minimize the chance we'll wind up
8254bff34e3Sthurlow 	 * with a partially complete request.
8264bff34e3Sthurlow 	 */
8274bff34e3Sthurlow 
8284bff34e3Sthurlow 	/* Shared lock for (possible) n_fid use. */
8294bff34e3Sthurlow 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
8304bff34e3Sthurlow 		return (EINTR);
8314bff34e3Sthurlow 	smb_credinit(&scred, curproc, cr);
8324bff34e3Sthurlow 
8334bff34e3Sthurlow 	/*
8344bff34e3Sthurlow 	 * Will we need an open handle for this setattr?
8354bff34e3Sthurlow 	 * If so, what rights will we need?
8364bff34e3Sthurlow 	 */
8374bff34e3Sthurlow 	if (mask & (AT_ATIME | AT_MTIME)) {
8384bff34e3Sthurlow 		rights |=
8394bff34e3Sthurlow 		    SA_RIGHT_FILE_WRITE_ATTRIBUTES |
8404bff34e3Sthurlow 		    GENERIC_RIGHT_ALL_ACCESS |
8414bff34e3Sthurlow 		    GENERIC_RIGHT_WRITE_ACCESS;
8424bff34e3Sthurlow 	}
8434bff34e3Sthurlow 	if (mask & AT_SIZE) {
8444bff34e3Sthurlow 		rights |=
8454bff34e3Sthurlow 		    SA_RIGHT_FILE_WRITE_DATA |
8464bff34e3Sthurlow 		    SA_RIGHT_FILE_APPEND_DATA;
8474bff34e3Sthurlow 		/*
8484bff34e3Sthurlow 		 * Only SIZE requires a handle.
8494bff34e3Sthurlow 		 * XXX May be more reliable to just
8504bff34e3Sthurlow 		 * always get the file handle here.
8514bff34e3Sthurlow 		 */
8524bff34e3Sthurlow 		error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
8534bff34e3Sthurlow 		if (error) {
8544bff34e3Sthurlow 			SMBVDEBUG("error %d opening %s\n",
8554bff34e3Sthurlow 			    error, np->n_rpath);
8564bff34e3Sthurlow 			goto out;
8574bff34e3Sthurlow 		}
8584bff34e3Sthurlow 		have_fid = 1;
8594bff34e3Sthurlow 	}
8604bff34e3Sthurlow 
8614bff34e3Sthurlow 
8624bff34e3Sthurlow 	/*
8634bff34e3Sthurlow 	 * If the server supports the UNIX extensions, right here is where
8644bff34e3Sthurlow 	 * we'd support changes to uid, gid, mode, and possibly va_flags.
8654bff34e3Sthurlow 	 * For now we claim to have made any such changes.
8664bff34e3Sthurlow 	 */
8674bff34e3Sthurlow 
8684bff34e3Sthurlow 	if (mask & AT_SIZE) {
8694bff34e3Sthurlow 		/*
8704bff34e3Sthurlow 		 * If the new file size is less than what the client sees as
8714bff34e3Sthurlow 		 * the file size, then just change the size and invalidate
8724bff34e3Sthurlow 		 * the pages.
8734bff34e3Sthurlow 		 * I am commenting this code at present because the function
8744bff34e3Sthurlow 		 * smbfs_putapage() is not yet implemented.
8754bff34e3Sthurlow 		 */
8764bff34e3Sthurlow 
8774bff34e3Sthurlow 		/*
8784bff34e3Sthurlow 		 * Set the file size to vap->va_size.
8794bff34e3Sthurlow 		 */
8804bff34e3Sthurlow 		ASSERT(have_fid);
8814bff34e3Sthurlow 		error = smbfs_smb_setfsize(np, fid, vap->va_size, &scred);
8824bff34e3Sthurlow 		if (error) {
8834bff34e3Sthurlow 			SMBVDEBUG("setsize error %d file %s\n",
8844bff34e3Sthurlow 			    error, np->n_rpath);
8854bff34e3Sthurlow 		} else {
8864bff34e3Sthurlow 			/*
8874bff34e3Sthurlow 			 * Darwin had code here to zero-extend.
8884bff34e3Sthurlow 			 * Tests indicate the server will zero-fill,
8894bff34e3Sthurlow 			 * so looks like we don't need to do this.
8904bff34e3Sthurlow 			 * Good thing, as this could take forever.
8914bff34e3Sthurlow 			 */
8924bff34e3Sthurlow 			mutex_enter(&np->r_statelock);
8934bff34e3Sthurlow 			np->r_size = vap->va_size;
8944bff34e3Sthurlow 			mutex_exit(&np->r_statelock);
8954bff34e3Sthurlow 			modified = 1;
8964bff34e3Sthurlow 		}
8974bff34e3Sthurlow 	}
8984bff34e3Sthurlow 
8994bff34e3Sthurlow 	/*
9004bff34e3Sthurlow 	 * XXX: When Solaris has create_time, set that too.
9014bff34e3Sthurlow 	 * Note: create_time is different from ctime.
9024bff34e3Sthurlow 	 */
9034bff34e3Sthurlow 	mtime = ((mask & AT_MTIME) ? &vap->va_mtime : 0);
9044bff34e3Sthurlow 	atime = ((mask & AT_ATIME) ? &vap->va_atime : 0);
9054bff34e3Sthurlow 
9064bff34e3Sthurlow 	if (mtime || atime) {
9074bff34e3Sthurlow 		/*
9084bff34e3Sthurlow 		 * If file is opened with write-attributes capability,
9094bff34e3Sthurlow 		 * we use handle-based calls.  If not, we use path-based ones.
9104bff34e3Sthurlow 		 */
9114bff34e3Sthurlow 		if (have_fid) {
9124bff34e3Sthurlow 			error = smbfs_smb_setfattr(np, fid,
9134bff34e3Sthurlow 			    np->n_dosattr, mtime, atime, &scred);
9144bff34e3Sthurlow 		} else {
9154bff34e3Sthurlow 			error = smbfs_smb_setpattr(np,
9164bff34e3Sthurlow 			    np->n_dosattr, mtime, atime, &scred);
9174bff34e3Sthurlow 		}
9184bff34e3Sthurlow 		if (error) {
9194bff34e3Sthurlow 			SMBVDEBUG("set times error %d file %s\n",
9204bff34e3Sthurlow 			    error, np->n_rpath);
9214bff34e3Sthurlow 		} else {
9224bff34e3Sthurlow 			/* XXX: set np->n_mtime, etc? */
9234bff34e3Sthurlow 			modified = 1;
9244bff34e3Sthurlow 		}
9254bff34e3Sthurlow 	}
9264bff34e3Sthurlow 
9274bff34e3Sthurlow out:
9284bff34e3Sthurlow 	if (modified) {
9294bff34e3Sthurlow 		/*
9304bff34e3Sthurlow 		 * Invalidate attribute cache in case if server doesn't set
9314bff34e3Sthurlow 		 * required attributes.
9324bff34e3Sthurlow 		 */
9334bff34e3Sthurlow 		smbfs_attr_cacheremove(np);
9344bff34e3Sthurlow 		/*
9354bff34e3Sthurlow 		 * XXX Darwin called _getattr here to
9364bff34e3Sthurlow 		 * update the mtime.  Should we?
9374bff34e3Sthurlow 		 */
9384bff34e3Sthurlow 	}
9394bff34e3Sthurlow 
9404bff34e3Sthurlow 	if (have_fid) {
9414bff34e3Sthurlow 		cerror = smbfs_smb_tmpclose(np, fid, &scred);
9424bff34e3Sthurlow 		if (cerror)
9434bff34e3Sthurlow 			SMBERROR("error %d closing %s\n",
9444bff34e3Sthurlow 			    cerror, np->n_rpath);
9454bff34e3Sthurlow 	}
9464bff34e3Sthurlow 
9474bff34e3Sthurlow 	smb_credrele(&scred);
9484bff34e3Sthurlow 	smbfs_rw_exit(&np->r_lkserlock);
9494bff34e3Sthurlow 
9504bff34e3Sthurlow 	return (error);
9514bff34e3Sthurlow }
9524bff34e3Sthurlow 
9534bff34e3Sthurlow /*
9544bff34e3Sthurlow  * smbfs_access_rwx()
9554bff34e3Sthurlow  * Common function for smbfs_access, etc.
9564bff34e3Sthurlow  *
9574bff34e3Sthurlow  * The security model implemented by the FS is unusual
9584bff34e3Sthurlow  * due to our "single user mounts" restriction.
9594bff34e3Sthurlow  *
9604bff34e3Sthurlow  * All access under a given mount point uses the CIFS
9614bff34e3Sthurlow  * credentials established by the owner of the mount.
9624bff34e3Sthurlow  * The Unix uid/gid/mode information is not (easily)
9634bff34e3Sthurlow  * provided by CIFS, and is instead fabricated using
9644bff34e3Sthurlow  * settings held in the mount structure.
9654bff34e3Sthurlow  *
9664bff34e3Sthurlow  * Most access checking is handled by the CIFS server,
9674bff34e3Sthurlow  * but we need sufficient Unix access checks here to
9684bff34e3Sthurlow  * prevent other local Unix users from having access
9694bff34e3Sthurlow  * to objects under this mount that the uid/gid/mode
9704bff34e3Sthurlow  * settings in the mount would not allow.
9714bff34e3Sthurlow  *
9724bff34e3Sthurlow  * With this model, there is a case where we need the
9734bff34e3Sthurlow  * ability to do an access check before we have the
9744bff34e3Sthurlow  * vnode for an object.  This function takes advantage
9754bff34e3Sthurlow  * of the fact that the uid/gid/mode is per mount, and
9764bff34e3Sthurlow  * avoids the need for a vnode.
9774bff34e3Sthurlow  *
9784bff34e3Sthurlow  * We still (sort of) need a vnode when we call
9794bff34e3Sthurlow  * secpolicy_vnode_access, but that only uses
9804bff34e3Sthurlow  * the vtype field, so we can use a pair of fake
9814bff34e3Sthurlow  * vnodes that have only v_type filled in.
9824bff34e3Sthurlow  *
9834bff34e3Sthurlow  * XXX: Later, add a new secpolicy_vtype_access()
9844bff34e3Sthurlow  * that takes the vtype instead of a vnode, and
9854bff34e3Sthurlow  * get rid of the tmpl_vxxx fake vnodes below.
9864bff34e3Sthurlow  */
9874bff34e3Sthurlow static int
9884bff34e3Sthurlow smbfs_access_rwx(vfs_t *vfsp, int vtype, int mode, cred_t *cr)
9894bff34e3Sthurlow {
9904bff34e3Sthurlow 	/* See the secpolicy call below. */
9914bff34e3Sthurlow 	static const vnode_t tmpl_vdir = { .v_type = VDIR };
9924bff34e3Sthurlow 	static const vnode_t tmpl_vreg = { .v_type = VREG };
9934bff34e3Sthurlow 	vattr_t		va;
9944bff34e3Sthurlow 	vnode_t		*tvp;
9954bff34e3Sthurlow 	struct smbmntinfo *smi = VFTOSMI(vfsp);
9964bff34e3Sthurlow 	int shift = 0;
9974bff34e3Sthurlow 
9984bff34e3Sthurlow 	/*
9994bff34e3Sthurlow 	 * Build our (fabricated) vnode attributes.
10004bff34e3Sthurlow 	 * XXX: Could make these templates in the
10014bff34e3Sthurlow 	 * per-mount struct and use them here.
10024bff34e3Sthurlow 	 */
10034bff34e3Sthurlow 	bzero(&va, sizeof (va));
10044bff34e3Sthurlow 	va.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
10054bff34e3Sthurlow 	va.va_type = vtype;
10064bff34e3Sthurlow 	va.va_mode = (vtype == VDIR) ?
10074bff34e3Sthurlow 	    smi->smi_args.dir_mode :
10084bff34e3Sthurlow 	    smi->smi_args.file_mode;
10094bff34e3Sthurlow 	va.va_uid = smi->smi_args.uid;
10104bff34e3Sthurlow 	va.va_gid = smi->smi_args.gid;
10114bff34e3Sthurlow 
10124bff34e3Sthurlow 	/*
10134bff34e3Sthurlow 	 * Disallow write attempts on read-only file systems,
10144bff34e3Sthurlow 	 * unless the file is a device or fifo node.  Note:
10154bff34e3Sthurlow 	 * Inline vn_is_readonly and IS_DEVVP here because
10164bff34e3Sthurlow 	 * we may not have a vnode ptr.  Original expr. was:
10174bff34e3Sthurlow 	 * (mode & VWRITE) && vn_is_readonly(vp) && !IS_DEVVP(vp))
10184bff34e3Sthurlow 	 */
10194bff34e3Sthurlow 	if ((mode & VWRITE) &&
10204bff34e3Sthurlow 	    (vfsp->vfs_flag & VFS_RDONLY) &&
10214bff34e3Sthurlow 	    !(vtype == VCHR || vtype == VBLK || vtype == VFIFO))
10224bff34e3Sthurlow 		return (EROFS);
10234bff34e3Sthurlow 
10244bff34e3Sthurlow 	/*
10254bff34e3Sthurlow 	 * Disallow attempts to access mandatory lock files.
10264bff34e3Sthurlow 	 * Similarly, expand MANDLOCK here.
10274bff34e3Sthurlow 	 * XXX: not sure we need this.
10284bff34e3Sthurlow 	 */
10294bff34e3Sthurlow 	if ((mode & (VWRITE | VREAD | VEXEC)) &&
10304bff34e3Sthurlow 	    va.va_type == VREG && MANDMODE(va.va_mode))
10314bff34e3Sthurlow 		return (EACCES);
10324bff34e3Sthurlow 
10334bff34e3Sthurlow 	/*
10344bff34e3Sthurlow 	 * Access check is based on only
10354bff34e3Sthurlow 	 * one of owner, group, public.
10364bff34e3Sthurlow 	 * If not owner, then check group.
10374bff34e3Sthurlow 	 * If not a member of the group,
10384bff34e3Sthurlow 	 * then check public access.
10394bff34e3Sthurlow 	 */
10404bff34e3Sthurlow 	if (crgetuid(cr) != va.va_uid) {
10414bff34e3Sthurlow 		shift += 3;
10424bff34e3Sthurlow 		if (!groupmember(va.va_gid, cr))
10434bff34e3Sthurlow 			shift += 3;
10444bff34e3Sthurlow 	}
10454bff34e3Sthurlow 	mode &= ~(va.va_mode << shift);
10464bff34e3Sthurlow 	if (mode == 0)
10474bff34e3Sthurlow 		return (0);
10484bff34e3Sthurlow 
10494bff34e3Sthurlow 	/*
10504bff34e3Sthurlow 	 * We need a vnode for secpolicy_vnode_access,
10514bff34e3Sthurlow 	 * but the only thing it looks at is v_type,
10524bff34e3Sthurlow 	 * so pass one of the templates above.
10534bff34e3Sthurlow 	 */
10544bff34e3Sthurlow 	tvp = (va.va_type == VDIR) ?
10554bff34e3Sthurlow 	    (vnode_t *)&tmpl_vdir :
10564bff34e3Sthurlow 	    (vnode_t *)&tmpl_vreg;
10574bff34e3Sthurlow 	return (secpolicy_vnode_access(cr, tvp, va.va_uid, mode));
10584bff34e3Sthurlow }
10594bff34e3Sthurlow 
10604bff34e3Sthurlow /*
10614bff34e3Sthurlow  * See smbfs_setattr
10624bff34e3Sthurlow  */
10634bff34e3Sthurlow static int
10644bff34e3Sthurlow smbfs_accessx(void *arg, int mode, cred_t *cr)
10654bff34e3Sthurlow {
10664bff34e3Sthurlow 	vnode_t *vp = arg;
10674bff34e3Sthurlow 	/*
10684bff34e3Sthurlow 	 * Note: The caller has checked the current zone,
10694bff34e3Sthurlow 	 * the SMI_DEAD and VFS_UNMOUNTED flags, etc.
10704bff34e3Sthurlow 	 */
10714bff34e3Sthurlow 	return (smbfs_access_rwx(vp->v_vfsp, vp->v_type, mode, cr));
10724bff34e3Sthurlow }
10734bff34e3Sthurlow 
10744bff34e3Sthurlow /*
10754bff34e3Sthurlow  * XXX
10764bff34e3Sthurlow  * This op should support PSARC 2007/403, Modified Access Checks for CIFS
10774bff34e3Sthurlow  */
10784bff34e3Sthurlow /* ARGSUSED */
10794bff34e3Sthurlow static int
10804bff34e3Sthurlow smbfs_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
10814bff34e3Sthurlow {
10824bff34e3Sthurlow 	vfs_t		*vfsp;
10834bff34e3Sthurlow 	smbmntinfo_t	*smi;
10844bff34e3Sthurlow 
10854bff34e3Sthurlow 	vfsp = vp->v_vfsp;
10864bff34e3Sthurlow 	smi = VFTOSMI(vfsp);
10874bff34e3Sthurlow 
10884bff34e3Sthurlow 	if (curproc->p_zone != smi->smi_zone)
10894bff34e3Sthurlow 		return (EIO);
10904bff34e3Sthurlow 
10914bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
10924bff34e3Sthurlow 		return (EIO);
10934bff34e3Sthurlow 
10944bff34e3Sthurlow 	return (smbfs_access_rwx(vfsp, vp->v_type, mode, cr));
10954bff34e3Sthurlow }
10964bff34e3Sthurlow 
10974bff34e3Sthurlow 
10984bff34e3Sthurlow /*
10994bff34e3Sthurlow  * Flush local dirty pages to stable storage on the server.
11004bff34e3Sthurlow  *
11014bff34e3Sthurlow  * If FNODSYNC is specified, then there is nothing to do because
11024bff34e3Sthurlow  * metadata changes are not cached on the client before being
11034bff34e3Sthurlow  * sent to the server.
11044bff34e3Sthurlow  *
11054bff34e3Sthurlow  * Currently, this is a no-op since we don't cache data, either.
11064bff34e3Sthurlow  */
11074bff34e3Sthurlow /* ARGSUSED */
11084bff34e3Sthurlow static int
11094bff34e3Sthurlow smbfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
11104bff34e3Sthurlow {
11114bff34e3Sthurlow 	int		error = 0;
11124bff34e3Sthurlow 	smbmntinfo_t	*smi;
11134bff34e3Sthurlow 
11144bff34e3Sthurlow 	smi = VTOSMI(vp);
11154bff34e3Sthurlow 
11164bff34e3Sthurlow 	if (curproc->p_zone != smi->smi_zone)
11174bff34e3Sthurlow 		return (EIO);
11184bff34e3Sthurlow 
11194bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
11204bff34e3Sthurlow 		return (EIO);
11214bff34e3Sthurlow 
11224bff34e3Sthurlow 	if ((syncflag & FNODSYNC) || IS_SWAPVP(vp))
11234bff34e3Sthurlow 		return (0);
11244bff34e3Sthurlow 
11254bff34e3Sthurlow 	return (error);
11264bff34e3Sthurlow }
11274bff34e3Sthurlow 
11284bff34e3Sthurlow /*
11294bff34e3Sthurlow  * Last reference to vnode went away.
11304bff34e3Sthurlow  */
11314bff34e3Sthurlow /* ARGSUSED */
11324bff34e3Sthurlow static void
11334bff34e3Sthurlow smbfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
11344bff34e3Sthurlow {
11354bff34e3Sthurlow 	smbnode_t	*np;
11364bff34e3Sthurlow 
11374bff34e3Sthurlow 	/*
11384bff34e3Sthurlow 	 * Don't "bail out" for VFS_UNMOUNTED here,
11394bff34e3Sthurlow 	 * as we want to do cleanup, etc.
11404bff34e3Sthurlow 	 * See also pcfs_inactive
11414bff34e3Sthurlow 	 */
11424bff34e3Sthurlow 
11434bff34e3Sthurlow 	np = VTOSMB(vp);
11444bff34e3Sthurlow 
11454bff34e3Sthurlow 	/*
11464bff34e3Sthurlow 	 * If this is coming from the wrong zone, we let someone in the right
11474bff34e3Sthurlow 	 * zone take care of it asynchronously.  We can get here due to
11484bff34e3Sthurlow 	 * VN_RELE() being called from pageout() or fsflush().  This call may
11494bff34e3Sthurlow 	 * potentially turn into an expensive no-op if, for instance, v_count
11504bff34e3Sthurlow 	 * gets incremented in the meantime, but it's still correct.
11514bff34e3Sthurlow 	 */
11524bff34e3Sthurlow 
11534bff34e3Sthurlow 	/*
11544bff34e3Sthurlow 	 * Some paranoia from the Darwin code:
11554bff34e3Sthurlow 	 * Make sure the FID was closed.
11564bff34e3Sthurlow 	 * If we see this, it's a bug!
11574bff34e3Sthurlow 	 *
11584bff34e3Sthurlow 	 * No rw_enter here, as this should be the
11594bff34e3Sthurlow 	 * last ref, and we're just looking...
11604bff34e3Sthurlow 	 */
11614bff34e3Sthurlow 	if (np->n_fidrefs > 0) {
11624bff34e3Sthurlow 		SMBVDEBUG("opencount %d fid %d file %s\n",
11634bff34e3Sthurlow 		    np->n_fidrefs, np->n_fid, np->n_rpath);
11644bff34e3Sthurlow 	}
11654bff34e3Sthurlow 	if (np->n_dirrefs > 0) {
11664bff34e3Sthurlow 		uint_t fid = (np->n_dirseq) ?
11674bff34e3Sthurlow 		    np->n_dirseq->f_Sid : 0;
11684bff34e3Sthurlow 		SMBVDEBUG("opencount %d fid %d dir %s\n",
11694bff34e3Sthurlow 		    np->n_dirrefs, fid, np->n_rpath);
11704bff34e3Sthurlow 	}
11714bff34e3Sthurlow 
11724bff34e3Sthurlow 	smb_addfree(np);
11734bff34e3Sthurlow }
11744bff34e3Sthurlow 
11754bff34e3Sthurlow /*
11764bff34e3Sthurlow  * Remote file system operations having to do with directory manipulation.
11774bff34e3Sthurlow  */
11784bff34e3Sthurlow /* ARGSUSED */
11794bff34e3Sthurlow static int
11804bff34e3Sthurlow smbfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
11814bff34e3Sthurlow 	int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
11824bff34e3Sthurlow 	int *direntflags, pathname_t *realpnp)
11834bff34e3Sthurlow {
11844bff34e3Sthurlow 	int		error;
11854bff34e3Sthurlow 	smbnode_t	*dnp;
11864bff34e3Sthurlow 	smbmntinfo_t	*smi;
11874bff34e3Sthurlow 
11884bff34e3Sthurlow 	smi = VTOSMI(dvp);
11894bff34e3Sthurlow 
11904bff34e3Sthurlow 	if (curproc->p_zone != smi->smi_zone)
11914bff34e3Sthurlow 		return (EPERM);
11924bff34e3Sthurlow 
11934bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
11944bff34e3Sthurlow 		return (EIO);
11954bff34e3Sthurlow 
11964bff34e3Sthurlow 	dnp = VTOSMB(dvp);
11974bff34e3Sthurlow 	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_READER, SMBINTR(dvp))) {
11984bff34e3Sthurlow 		error = EINTR;
11994bff34e3Sthurlow 		goto out;
12004bff34e3Sthurlow 	}
12014bff34e3Sthurlow 
12024bff34e3Sthurlow 	error = smbfslookup(dvp, nm, vpp, cr, 1, ct);
12034bff34e3Sthurlow 
12044bff34e3Sthurlow 	smbfs_rw_exit(&dnp->r_rwlock);
12054bff34e3Sthurlow 
12064bff34e3Sthurlow out:
12074bff34e3Sthurlow 	return (error);
12084bff34e3Sthurlow }
12094bff34e3Sthurlow 
12104bff34e3Sthurlow /* ARGSUSED */
12114bff34e3Sthurlow static int
12124bff34e3Sthurlow smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, int dnlc,
12134bff34e3Sthurlow 	caller_context_t *ct)
12144bff34e3Sthurlow {
12154bff34e3Sthurlow 	int		error;
12164bff34e3Sthurlow 	int		supplen; /* supported length */
12174bff34e3Sthurlow 	vnode_t		*vp;
12184bff34e3Sthurlow 	smbnode_t	*dnp;
12194bff34e3Sthurlow 	smbmntinfo_t	*smi;
12204bff34e3Sthurlow 	/* struct smb_vc	*vcp; */
12214bff34e3Sthurlow 	const char	*name = (const char *)nm;
12224bff34e3Sthurlow 	int 		nmlen = strlen(nm);
12234bff34e3Sthurlow 	int 		rplen;
12244bff34e3Sthurlow 	struct smb_cred scred;
12254bff34e3Sthurlow 	struct smbfattr fa;
12264bff34e3Sthurlow 
12274bff34e3Sthurlow 	smi = VTOSMI(dvp);
12284bff34e3Sthurlow 	dnp = VTOSMB(dvp);
12294bff34e3Sthurlow 
12304bff34e3Sthurlow 	ASSERT(curproc->p_zone == smi->smi_zone);
12314bff34e3Sthurlow 
12324bff34e3Sthurlow #ifdef NOT_YET
12334bff34e3Sthurlow 	vcp = SSTOVC(smi->smi_share);
12344bff34e3Sthurlow 
12354bff34e3Sthurlow 	/* XXX: Should compute this once and store it in smbmntinfo_t */
12364bff34e3Sthurlow 	supplen = (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) ? 255 : 12;
12374bff34e3Sthurlow #else
12384bff34e3Sthurlow 	supplen = 255;
12394bff34e3Sthurlow #endif
12404bff34e3Sthurlow 
12414bff34e3Sthurlow 	/*
12424bff34e3Sthurlow 	 * RWlock must be held, either reader or writer.
12434bff34e3Sthurlow 	 * XXX: Can we check without looking directly
12444bff34e3Sthurlow 	 * inside the struct smbfs_rwlock_t?
12454bff34e3Sthurlow 	 */
12464bff34e3Sthurlow 	ASSERT(dnp->r_rwlock.count != 0);
12474bff34e3Sthurlow 
12484bff34e3Sthurlow 	/*
12494bff34e3Sthurlow 	 * If lookup is for "", just return dvp.  Don't need
12504bff34e3Sthurlow 	 * to send it over the wire, look it up in the dnlc,
12514bff34e3Sthurlow 	 * or perform any access checks.
12524bff34e3Sthurlow 	 */
12534bff34e3Sthurlow 	if (nmlen == 0) {
12544bff34e3Sthurlow 		VN_HOLD(dvp);
12554bff34e3Sthurlow 		*vpp = dvp;
12564bff34e3Sthurlow 		return (0);
12574bff34e3Sthurlow 	}
12584bff34e3Sthurlow 
12594bff34e3Sthurlow 	/* if the name is longer that what is supported, return an error */
12604bff34e3Sthurlow 	if (nmlen > supplen)
12614bff34e3Sthurlow 		return (ENAMETOOLONG);
12624bff34e3Sthurlow 
12634bff34e3Sthurlow 	/*
12644bff34e3Sthurlow 	 * Avoid surprises with characters that are
12654bff34e3Sthurlow 	 * illegal in Windows file names.
12664bff34e3Sthurlow 	 * Todo: CATIA mappings  XXX
12674bff34e3Sthurlow 	 */
12684bff34e3Sthurlow 	if (strpbrk(nm, illegal_chars))
12694bff34e3Sthurlow 		return (EINVAL);
12704bff34e3Sthurlow 
12714bff34e3Sthurlow 	/* if the dvp is not a directory, return an error */
12724bff34e3Sthurlow 	if (dvp->v_type != VDIR)
12734bff34e3Sthurlow 		return (ENOTDIR);
12744bff34e3Sthurlow 
12754bff34e3Sthurlow 	/* Need search permission in the directory. */
12764bff34e3Sthurlow 	error = smbfs_access(dvp, VEXEC, 0, cr, ct);
12774bff34e3Sthurlow 	if (error)
12784bff34e3Sthurlow 		return (error);
12794bff34e3Sthurlow 
12804bff34e3Sthurlow 	/*
12814bff34e3Sthurlow 	 * If lookup is for ".", just return dvp.  Don't need
12824bff34e3Sthurlow 	 * to send it over the wire or look it up in the dnlc,
12834bff34e3Sthurlow 	 * just need to check access (done above).
12844bff34e3Sthurlow 	 */
12854bff34e3Sthurlow 	if (nmlen == 1 && name[0] == '.') {
12864bff34e3Sthurlow 		VN_HOLD(dvp);
12874bff34e3Sthurlow 		*vpp = dvp;
12884bff34e3Sthurlow 		return (0);
12894bff34e3Sthurlow 	}
12904bff34e3Sthurlow 
12914bff34e3Sthurlow #ifdef NOT_YET
12924bff34e3Sthurlow 	if (dnlc) {
12934bff34e3Sthurlow 	/*
12944bff34e3Sthurlow 	 * NOTE: search the dnlc here
12954bff34e3Sthurlow 	 */
12964bff34e3Sthurlow 	}
12974bff34e3Sthurlow #endif
12984bff34e3Sthurlow 
12994bff34e3Sthurlow 	/*
13004bff34e3Sthurlow 	 * Handle lookup of ".." which is quite tricky,
13014bff34e3Sthurlow 	 * because the protocol gives us little help.
13024bff34e3Sthurlow 	 *
13034bff34e3Sthurlow 	 * We keep full pathnames (as seen on the server)
13044bff34e3Sthurlow 	 * so we can just trim off the last component to
13054bff34e3Sthurlow 	 * get the full pathname of the parent.  Note:
13064bff34e3Sthurlow 	 * We don't actually copy and modify, but just
13074bff34e3Sthurlow 	 * compute the trimmed length and pass that with
13084bff34e3Sthurlow 	 * the current dir path (not null terminated).
13094bff34e3Sthurlow 	 *
13104bff34e3Sthurlow 	 * We don't go over-the-wire to get attributes
13114bff34e3Sthurlow 	 * for ".." because we know it's a directory,
13124bff34e3Sthurlow 	 * and we can just leave the rest "stale"
13134bff34e3Sthurlow 	 * until someone does a getattr.
13144bff34e3Sthurlow 	 */
13154bff34e3Sthurlow 	if (nmlen == 2 && name[0] == '.' && name[1] == '.') {
13164bff34e3Sthurlow 		if (dvp->v_flag & VROOT) {
13174bff34e3Sthurlow 			/*
13184bff34e3Sthurlow 			 * Already at the root.  This can happen
13194bff34e3Sthurlow 			 * with directory listings at the root,
13204bff34e3Sthurlow 			 * which lookup "." and ".." to get the
13214bff34e3Sthurlow 			 * inode numbers.  Let ".." be the same
13224bff34e3Sthurlow 			 * as "." in the FS root.
13234bff34e3Sthurlow 			 */
13244bff34e3Sthurlow 			VN_HOLD(dvp);
13254bff34e3Sthurlow 			*vpp = dvp;
13264bff34e3Sthurlow 			return (0);
13274bff34e3Sthurlow 		}
13284bff34e3Sthurlow 
13294bff34e3Sthurlow 		/*
13304bff34e3Sthurlow 		 * Find the parent path length.
13314bff34e3Sthurlow 		 */
13324bff34e3Sthurlow 		rplen = dnp->n_rplen;
13334bff34e3Sthurlow 		ASSERT(rplen > 0);
13344bff34e3Sthurlow 		while (--rplen >= 0) {
13354bff34e3Sthurlow 			if (dnp->n_rpath[rplen] == '\\')
13364bff34e3Sthurlow 				break;
13374bff34e3Sthurlow 		}
13384bff34e3Sthurlow 		if (rplen == 0) {
13394bff34e3Sthurlow 			/* Found our way to the root. */
13404bff34e3Sthurlow 			vp = SMBTOV(smi->smi_root);
13414bff34e3Sthurlow 			VN_HOLD(vp);
13424bff34e3Sthurlow 			*vpp = vp;
13434bff34e3Sthurlow 			return (0);
13444bff34e3Sthurlow 		}
13454bff34e3Sthurlow 		vp = smbfs_make_node(dvp->v_vfsp,
13464bff34e3Sthurlow 		    dnp->n_rpath, rplen,
13474bff34e3Sthurlow 		    NULL, 0, NULL);
13484bff34e3Sthurlow 		if (vp == NULL) {
13494bff34e3Sthurlow 			return (ENOENT);
13504bff34e3Sthurlow 		}
13514bff34e3Sthurlow 		vp->v_type = VDIR;
13524bff34e3Sthurlow 
13534bff34e3Sthurlow 		/* Success! */
13544bff34e3Sthurlow 		*vpp = vp;
13554bff34e3Sthurlow 		return (0);
13564bff34e3Sthurlow 	}
13574bff34e3Sthurlow 
13584bff34e3Sthurlow 	/*
13594bff34e3Sthurlow 	 * Normal lookup of a child node.
13604bff34e3Sthurlow 	 * Note we handled "." and ".." above.
13614bff34e3Sthurlow 	 *
13624bff34e3Sthurlow 	 * First, go over-the-wire to get the
13634bff34e3Sthurlow 	 * node type (and attributes).
13644bff34e3Sthurlow 	 */
13654bff34e3Sthurlow 	smb_credinit(&scred, curproc, cr);
13664bff34e3Sthurlow 	/* Note: this can allocate a new "name" */
13674bff34e3Sthurlow 	error = smbfs_smb_lookup(dnp, &name, &nmlen, &fa, &scred);
13684bff34e3Sthurlow 	smb_credrele(&scred);
13694bff34e3Sthurlow 	if (error)
13704bff34e3Sthurlow 		goto out;
13714bff34e3Sthurlow 
13724bff34e3Sthurlow 	/*
13734bff34e3Sthurlow 	 * Find or create the node.
13744bff34e3Sthurlow 	 */
13754bff34e3Sthurlow 	error = smbfs_nget(dvp, name, nmlen, &fa, &vp);
13764bff34e3Sthurlow 	if (error)
13774bff34e3Sthurlow 		goto out;
13784bff34e3Sthurlow 
13794bff34e3Sthurlow 	/* Success! */
13804bff34e3Sthurlow 	*vpp = vp;
13814bff34e3Sthurlow 
13824bff34e3Sthurlow out:
13834bff34e3Sthurlow 	/* smbfs_smb_lookup may have allocated name. */
13844bff34e3Sthurlow 	if (name != nm)
13854bff34e3Sthurlow 		smbfs_name_free(name, nmlen);
13864bff34e3Sthurlow 
13874bff34e3Sthurlow 	return (error);
13884bff34e3Sthurlow }
13894bff34e3Sthurlow 
13904bff34e3Sthurlow /*
13914bff34e3Sthurlow  * XXX
13924bff34e3Sthurlow  * vsecattr_t is new to build 77, and we need to eventually support
13934bff34e3Sthurlow  * it in order to create an ACL when an object is created.
13944bff34e3Sthurlow  *
13954bff34e3Sthurlow  * This op should support the new FIGNORECASE flag for case-insensitive
13964bff34e3Sthurlow  * lookups, per PSARC 2007/244.
13974bff34e3Sthurlow  */
13984bff34e3Sthurlow /* ARGSUSED */
13994bff34e3Sthurlow static int
14004bff34e3Sthurlow smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
14014bff34e3Sthurlow 	int mode, vnode_t **vpp, cred_t *cr, int lfaware, caller_context_t *ct,
14024bff34e3Sthurlow 	vsecattr_t *vsecp)
14034bff34e3Sthurlow {
14044bff34e3Sthurlow 	int		error;
14054bff34e3Sthurlow 	int		cerror;
14064bff34e3Sthurlow 	vfs_t		*vfsp;
14074bff34e3Sthurlow 	vnode_t		*vp;
14084bff34e3Sthurlow #ifdef NOT_YET
14094bff34e3Sthurlow 	smbnode_t	*np;
14104bff34e3Sthurlow #endif
14114bff34e3Sthurlow 	smbnode_t	*dnp;
14124bff34e3Sthurlow 	smbmntinfo_t	*smi;
14134bff34e3Sthurlow 	struct vattr	vattr;
14144bff34e3Sthurlow 	struct smbfattr	fattr;
14154bff34e3Sthurlow 	struct smb_cred	scred;
14164bff34e3Sthurlow 	const char *name = (const char *)nm;
14174bff34e3Sthurlow 	int		nmlen = strlen(nm);
14184bff34e3Sthurlow 	uint32_t	disp;
14194bff34e3Sthurlow 	uint16_t	fid;
14204bff34e3Sthurlow 
14214bff34e3Sthurlow 	vfsp = dvp->v_vfsp;
14224bff34e3Sthurlow 	smi = VFTOSMI(vfsp);
14234bff34e3Sthurlow 	dnp = VTOSMB(dvp);
14244bff34e3Sthurlow 	vp = NULL;
14254bff34e3Sthurlow 
14264bff34e3Sthurlow 	if (curproc->p_zone != smi->smi_zone)
14274bff34e3Sthurlow 		return (EPERM);
14284bff34e3Sthurlow 
14294bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
14304bff34e3Sthurlow 		return (EIO);
14314bff34e3Sthurlow 
14324bff34e3Sthurlow 	/*
14334bff34e3Sthurlow 	 * Note: this may break mknod(2) calls to create a directory,
14344bff34e3Sthurlow 	 * but that's obscure use.  Some other filesystems do this.
14354bff34e3Sthurlow 	 * XXX: Later, redirect VDIR type here to _mkdir.
14364bff34e3Sthurlow 	 */
14374bff34e3Sthurlow 	if (va->va_type != VREG)
14384bff34e3Sthurlow 		return (EINVAL);
14394bff34e3Sthurlow 
14404bff34e3Sthurlow 	/*
14414bff34e3Sthurlow 	 * If the pathname is "", just use dvp, no checks.
14424bff34e3Sthurlow 	 * Do this outside of the rwlock (like zfs).
14434bff34e3Sthurlow 	 */
14444bff34e3Sthurlow 	if (nmlen == 0) {
14454bff34e3Sthurlow 		VN_HOLD(dvp);
14464bff34e3Sthurlow 		*vpp = dvp;
14474bff34e3Sthurlow 		return (0);
14484bff34e3Sthurlow 	}
14494bff34e3Sthurlow 
14504bff34e3Sthurlow 	/* Don't allow "." or ".." through here. */
14514bff34e3Sthurlow 	if ((nmlen == 1 && name[0] == '.') ||
14524bff34e3Sthurlow 	    (nmlen == 2 && name[0] == '.' && name[1] == '.'))
14534bff34e3Sthurlow 		return (EISDIR);
14544bff34e3Sthurlow 
14554bff34e3Sthurlow 	/*
14564bff34e3Sthurlow 	 * We make a copy of the attributes because the caller does not
14574bff34e3Sthurlow 	 * expect us to change what va points to.
14584bff34e3Sthurlow 	 */
14594bff34e3Sthurlow 	vattr = *va;
14604bff34e3Sthurlow 
14614bff34e3Sthurlow 	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
14624bff34e3Sthurlow 		return (EINTR);
14634bff34e3Sthurlow 	smb_credinit(&scred, curproc, cr);
14644bff34e3Sthurlow 
14654bff34e3Sthurlow 	/*
14664bff34e3Sthurlow 	 * XXX: Do we need r_lkserlock too?
14674bff34e3Sthurlow 	 * No use of any shared fid or fctx...
14684bff34e3Sthurlow 	 */
14694bff34e3Sthurlow 
14704bff34e3Sthurlow 	/*
14714bff34e3Sthurlow 	 * NFS needs to go over the wire, just to be sure whether the
14724bff34e3Sthurlow 	 * file exists or not.  Using the DNLC can be dangerous in
14734bff34e3Sthurlow 	 * this case when making a decision regarding existence.
14744bff34e3Sthurlow 	 *
14754bff34e3Sthurlow 	 * The SMB protocol does NOT really need to go OTW here
14764bff34e3Sthurlow 	 * thanks to the expressive NTCREATE disposition values.
14774bff34e3Sthurlow 	 * Unfortunately, to do Unix access checks correctly,
14784bff34e3Sthurlow 	 * we need to know if the object already exists.
14794bff34e3Sthurlow 	 * When the object does not exist, we need VWRITE on
14804bff34e3Sthurlow 	 * the directory.  Note: smbfslookup() checks VEXEC.
14814bff34e3Sthurlow 	 */
14824bff34e3Sthurlow 	error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
14834bff34e3Sthurlow 	if (error == 0) {
14844bff34e3Sthurlow 		/*
14854bff34e3Sthurlow 		 * file already exists
14864bff34e3Sthurlow 		 */
14874bff34e3Sthurlow 		if (exclusive == EXCL) {
14884bff34e3Sthurlow 			error = EEXIST;
14894bff34e3Sthurlow 			goto out;
14904bff34e3Sthurlow 		}
14914bff34e3Sthurlow 		/*
14924bff34e3Sthurlow 		 * Verify requested access.
14934bff34e3Sthurlow 		 */
14944bff34e3Sthurlow 		error = smbfs_access(vp, mode, 0, cr, ct);
14954bff34e3Sthurlow 		if (error)
14964bff34e3Sthurlow 			goto out;
14974bff34e3Sthurlow 
14984bff34e3Sthurlow 		/*
14994bff34e3Sthurlow 		 * Truncate (if requested).
15004bff34e3Sthurlow 		 */
15014bff34e3Sthurlow 		if ((vattr.va_mask & AT_SIZE) && vattr.va_size == 0) {
15024bff34e3Sthurlow 			vattr.va_mask = AT_SIZE;
15034bff34e3Sthurlow 			error = smbfssetattr(vp, &vattr, 0, cr);
15044bff34e3Sthurlow 			if (error)
15054bff34e3Sthurlow 				goto out;
15064bff34e3Sthurlow 		}
15074bff34e3Sthurlow 		/* Success! */
15084bff34e3Sthurlow #ifdef NOT_YET
15094bff34e3Sthurlow 		vnevent_create(vp, ct);
15104bff34e3Sthurlow #endif
15114bff34e3Sthurlow 		*vpp = vp;
15124bff34e3Sthurlow 		goto out;
15134bff34e3Sthurlow 	}
15144bff34e3Sthurlow 
15154bff34e3Sthurlow 	/*
15164bff34e3Sthurlow 	 * The file did not exist.  Need VWRITE in the directory.
15174bff34e3Sthurlow 	 */
15184bff34e3Sthurlow 	error = smbfs_access(dvp, VWRITE, 0, cr, ct);
15194bff34e3Sthurlow 	if (error)
15204bff34e3Sthurlow 		goto out;
15214bff34e3Sthurlow 
15224bff34e3Sthurlow 	/*
15234bff34e3Sthurlow 	 * Now things get tricky.  We also need to check the
15244bff34e3Sthurlow 	 * requested open mode against the file we may create.
15254bff34e3Sthurlow 	 * See comments at smbfs_access_rwx
15264bff34e3Sthurlow 	 */
15274bff34e3Sthurlow 	error = smbfs_access_rwx(vfsp, VREG, mode, cr);
15284bff34e3Sthurlow 	if (error)
15294bff34e3Sthurlow 		goto out;
15304bff34e3Sthurlow 
15314bff34e3Sthurlow #ifdef NOT_YET
15324bff34e3Sthurlow 	/* remove the entry from the negative entry from the dnlc */
15334bff34e3Sthurlow 	dnlc_remove(dvp, name);
15344bff34e3Sthurlow #endif
15354bff34e3Sthurlow 
15364bff34e3Sthurlow 	/*
15374bff34e3Sthurlow 	 * Now the code derived from Darwin,
15384bff34e3Sthurlow 	 * but with greater use of NT_CREATE
15394bff34e3Sthurlow 	 * disposition options.  Much changed.
15404bff34e3Sthurlow 	 *
15414bff34e3Sthurlow 	 * Create (or open) a new child node.
15424bff34e3Sthurlow 	 * Note we handled "." and ".." above.
15434bff34e3Sthurlow 	 */
15444bff34e3Sthurlow 
15454bff34e3Sthurlow 	if (exclusive == EXCL)
15464bff34e3Sthurlow 		disp = NTCREATEX_DISP_CREATE;
15474bff34e3Sthurlow 	else {
15484bff34e3Sthurlow 		/* Truncate regular files if requested. */
15494bff34e3Sthurlow 		if ((va->va_type == VREG) &&
15504bff34e3Sthurlow 		    (va->va_mask & AT_SIZE) &&
15514bff34e3Sthurlow 		    (va->va_size == 0))
15524bff34e3Sthurlow 			disp = NTCREATEX_DISP_OVERWRITE_IF;
15534bff34e3Sthurlow 		else
15544bff34e3Sthurlow 			disp = NTCREATEX_DISP_OPEN_IF;
15554bff34e3Sthurlow 	}
15564bff34e3Sthurlow 	error = smbfs_smb_create(dnp, name, nmlen, &scred, &fid, disp, 0);
15574bff34e3Sthurlow 	if (error)
15584bff34e3Sthurlow 		goto out;
15594bff34e3Sthurlow 
15604bff34e3Sthurlow 	/*
15614bff34e3Sthurlow 	 * XXX: Missing some code here to deal with
15624bff34e3Sthurlow 	 * the case where we opened an existing file,
15634bff34e3Sthurlow 	 * it's size is larger than 32-bits, and we're
15644bff34e3Sthurlow 	 * setting the size from a process that's not
15654bff34e3Sthurlow 	 * aware of large file offsets.  i.e.
15664bff34e3Sthurlow 	 * from the NFS3 code:
15674bff34e3Sthurlow 	 */
15684bff34e3Sthurlow #if NOT_YET /* XXX */
15694bff34e3Sthurlow 	if ((vattr.va_mask & AT_SIZE) &&
15704bff34e3Sthurlow 	    vp->v_type == VREG) {
15714bff34e3Sthurlow 		np = VTOSMB(vp);
15724bff34e3Sthurlow 		/*
15734bff34e3Sthurlow 		 * Check here for large file handled
15744bff34e3Sthurlow 		 * by LF-unaware process (as
15754bff34e3Sthurlow 		 * ufs_create() does)
15764bff34e3Sthurlow 		 */
15774bff34e3Sthurlow 		if (!(lfaware & FOFFMAX)) {
15784bff34e3Sthurlow 			mutex_enter(&np->r_statelock);
15794bff34e3Sthurlow 			if (np->r_size > MAXOFF32_T)
15804bff34e3Sthurlow 				error = EOVERFLOW;
15814bff34e3Sthurlow 			mutex_exit(&np->r_statelock);
15824bff34e3Sthurlow 		}
15834bff34e3Sthurlow 		if (!error) {
15844bff34e3Sthurlow 			vattr.va_mask = AT_SIZE;
15854bff34e3Sthurlow 			error = smbfssetattr(vp,
15864bff34e3Sthurlow 			    &vattr, 0, cr);
15874bff34e3Sthurlow 		}
15884bff34e3Sthurlow 	}
15894bff34e3Sthurlow #endif /* XXX */
15904bff34e3Sthurlow 	/*
15914bff34e3Sthurlow 	 * Should use the fid to get/set the size
15924bff34e3Sthurlow 	 * while we have it opened here.  See above.
15934bff34e3Sthurlow 	 */
15944bff34e3Sthurlow 
15954bff34e3Sthurlow 	cerror = smbfs_smb_close(smi->smi_share, fid, NULL, &scred);
15964bff34e3Sthurlow 	if (cerror)
15974bff34e3Sthurlow 		SMBERROR("error %d closing %s\\%s\n",
15984bff34e3Sthurlow 		    cerror, dnp->n_rpath, name);
15994bff34e3Sthurlow 
16004bff34e3Sthurlow 	/*
16014bff34e3Sthurlow 	 * In the open case, the name may differ a little
16024bff34e3Sthurlow 	 * from what we passed to create (case, etc.)
16034bff34e3Sthurlow 	 * so call lookup to get the (opened) name.
16044bff34e3Sthurlow 	 *
16054bff34e3Sthurlow 	 * XXX: Could avoid this extra lookup if the
16064bff34e3Sthurlow 	 * "createact" result from NT_CREATE says we
16074bff34e3Sthurlow 	 * created the object.
16084bff34e3Sthurlow 	 */
16094bff34e3Sthurlow 	error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred);
16104bff34e3Sthurlow 	if (error)
16114bff34e3Sthurlow 		goto out;
16124bff34e3Sthurlow 
16134bff34e3Sthurlow 	/* update attr and directory cache */
16144bff34e3Sthurlow 	smbfs_attr_touchdir(dnp);
16154bff34e3Sthurlow 
16164bff34e3Sthurlow 	error = smbfs_nget(dvp, name, nmlen, &fattr, &vp);
16174bff34e3Sthurlow 	if (error)
16184bff34e3Sthurlow 		goto out;
16194bff34e3Sthurlow 
16204bff34e3Sthurlow #ifdef NOT_YET
16214bff34e3Sthurlow 	dnlc_update(dvp, name, vp);
16224bff34e3Sthurlow 	/* XXX invalidate pages if we truncated? */
16234bff34e3Sthurlow #endif
16244bff34e3Sthurlow 
16254bff34e3Sthurlow 	/* Success! */
16264bff34e3Sthurlow 	*vpp = vp;
16274bff34e3Sthurlow 	error = 0;
16284bff34e3Sthurlow 
16294bff34e3Sthurlow out:
16304bff34e3Sthurlow 	smb_credrele(&scred);
16314bff34e3Sthurlow 	if (name != nm)
16324bff34e3Sthurlow 		smbfs_name_free(name, nmlen);
16334bff34e3Sthurlow 	smbfs_rw_exit(&dnp->r_rwlock);
16344bff34e3Sthurlow 	return (error);
16354bff34e3Sthurlow }
16364bff34e3Sthurlow 
16374bff34e3Sthurlow /*
16384bff34e3Sthurlow  * XXX
16394bff34e3Sthurlow  * This op should support the new FIGNORECASE flag for case-insensitive
16404bff34e3Sthurlow  * lookups, per PSARC 2007/244.
16414bff34e3Sthurlow  */
16424bff34e3Sthurlow /* ARGSUSED */
16434bff34e3Sthurlow static int
16444bff34e3Sthurlow smbfs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct,
16454bff34e3Sthurlow 	int flags)
16464bff34e3Sthurlow {
16474bff34e3Sthurlow 	int		error;
16484bff34e3Sthurlow 	vnode_t		*vp;
16494bff34e3Sthurlow 	smbnode_t	*np;
16504bff34e3Sthurlow 	smbnode_t	*dnp;
16514bff34e3Sthurlow 	struct smb_cred	scred;
16524bff34e3Sthurlow 	/* enum smbfsstat status; */
16534bff34e3Sthurlow 	smbmntinfo_t	*smi;
16544bff34e3Sthurlow 
16554bff34e3Sthurlow 	smi = VTOSMI(dvp);
16564bff34e3Sthurlow 
16574bff34e3Sthurlow 	if (curproc->p_zone != smi->smi_zone)
16584bff34e3Sthurlow 		return (EPERM);
16594bff34e3Sthurlow 
16604bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
16614bff34e3Sthurlow 		return (EIO);
16624bff34e3Sthurlow 
16634bff34e3Sthurlow 	dnp = VTOSMB(dvp);
16644bff34e3Sthurlow 	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
16654bff34e3Sthurlow 		return (EINTR);
16664bff34e3Sthurlow 
16674bff34e3Sthurlow 	/*
16684bff34e3Sthurlow 	 * Verify access to the dirctory.
16694bff34e3Sthurlow 	 */
16704bff34e3Sthurlow 	error = smbfs_access(dvp, VWRITE|VEXEC, 0, cr, ct);
16714bff34e3Sthurlow 	if (error)
16724bff34e3Sthurlow 		goto out;
16734bff34e3Sthurlow 
16744bff34e3Sthurlow 	/*
16754bff34e3Sthurlow 	 * NOTE:  the darwin code gets the "vp" passed in so it looks
16764bff34e3Sthurlow 	 * like the "vp" has probably been "lookup"ed by the VFS layer.
16774bff34e3Sthurlow 	 * It looks like we will need to lookup the vp to check the
16784bff34e3Sthurlow 	 * caches and check if the object being deleted is a directory.
16794bff34e3Sthurlow 	 */
16804bff34e3Sthurlow 	error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
16814bff34e3Sthurlow 	if (error)
16824bff34e3Sthurlow 		goto out;
16834bff34e3Sthurlow 
16844bff34e3Sthurlow 	/* Never allow link/unlink directories on CIFS. */
16854bff34e3Sthurlow 	if (vp->v_type == VDIR) {
16864bff34e3Sthurlow 		VN_RELE(vp);
16874bff34e3Sthurlow 		error = EPERM;
16884bff34e3Sthurlow 		goto out;
16894bff34e3Sthurlow 	}
16904bff34e3Sthurlow 
16914bff34e3Sthurlow #ifdef NOT_YET
16924bff34e3Sthurlow 	/*
16934bff34e3Sthurlow 	 * First just remove the entry from the name cache, as it
16944bff34e3Sthurlow 	 * is most likely the only entry for this vp.
16954bff34e3Sthurlow 	 */
16964bff34e3Sthurlow 	dnlc_remove(dvp, nm);
16974bff34e3Sthurlow 
16984bff34e3Sthurlow 	/*
16994bff34e3Sthurlow 	 * If the file has a v_count > 1 then there may be more than one
17004bff34e3Sthurlow 	 * entry in the name cache due multiple links or an open file,
17014bff34e3Sthurlow 	 * but we don't have the real reference count so flush all
17024bff34e3Sthurlow 	 * possible entries.
17034bff34e3Sthurlow 	 */
17044bff34e3Sthurlow 	if (vp->v_count > 1)
17054bff34e3Sthurlow 		dnlc_purge_vp(vp);
17064bff34e3Sthurlow #endif /* NOT_YET */
17074bff34e3Sthurlow 
17084bff34e3Sthurlow 	/*
17094bff34e3Sthurlow 	 * Now we have the real reference count on the vnode
17104bff34e3Sthurlow 	 */
17114bff34e3Sthurlow 	np = VTOSMB(vp);
17124bff34e3Sthurlow 	mutex_enter(&np->r_statelock);
17134bff34e3Sthurlow 	if (vp->v_count > 1) {
17144bff34e3Sthurlow 		/*
17154bff34e3Sthurlow 		 * NFS does a rename on remove here.
17164bff34e3Sthurlow 		 * Probably not applicable for SMB.
17174bff34e3Sthurlow 		 * Like Darwin, just return EBUSY.
17184bff34e3Sthurlow 		 *
17194bff34e3Sthurlow 		 * XXX: Todo - Ask the server to set the
17204bff34e3Sthurlow 		 * set the delete-on-close flag.
17214bff34e3Sthurlow 		 */
17224bff34e3Sthurlow 		mutex_exit(&np->r_statelock);
17234bff34e3Sthurlow 		error = EBUSY;
17244bff34e3Sthurlow 		goto out;
17254bff34e3Sthurlow 	} else {
17264bff34e3Sthurlow 		mutex_exit(&np->r_statelock);
17274bff34e3Sthurlow 
17284bff34e3Sthurlow 		smb_credinit(&scred, curproc, cr);
17294bff34e3Sthurlow 		error = smbfs_smb_delete(np, &scred, NULL, 0, 0);
17304bff34e3Sthurlow 		smb_credrele(&scred);
17314bff34e3Sthurlow 
17324bff34e3Sthurlow 	}
17334bff34e3Sthurlow 
17344bff34e3Sthurlow 	VN_RELE(vp);
17354bff34e3Sthurlow 
17364bff34e3Sthurlow out:
17374bff34e3Sthurlow 	smbfs_rw_exit(&dnp->r_rwlock);
17384bff34e3Sthurlow 
17394bff34e3Sthurlow 	return (error);
17404bff34e3Sthurlow }
17414bff34e3Sthurlow 
17424bff34e3Sthurlow 
17434bff34e3Sthurlow /*
17444bff34e3Sthurlow  * XXX
17454bff34e3Sthurlow  * This op should support the new FIGNORECASE flag for case-insensitive
17464bff34e3Sthurlow  * lookups, per PSARC 2007/244.
17474bff34e3Sthurlow  */
17484bff34e3Sthurlow /* ARGSUSED */
17494bff34e3Sthurlow static int
17504bff34e3Sthurlow smbfs_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
17514bff34e3Sthurlow 	caller_context_t *ct, int flags)
17524bff34e3Sthurlow {
17534bff34e3Sthurlow 	/* vnode_t		*realvp; */
17544bff34e3Sthurlow 
17554bff34e3Sthurlow 	if (curproc->p_zone != VTOSMI(odvp)->smi_zone ||
17564bff34e3Sthurlow 	    curproc->p_zone != VTOSMI(ndvp)->smi_zone)
17574bff34e3Sthurlow 		return (EPERM);
17584bff34e3Sthurlow 
17594bff34e3Sthurlow 	if (VTOSMI(odvp)->smi_flags & SMI_DEAD ||
17604bff34e3Sthurlow 	    VTOSMI(ndvp)->smi_flags & SMI_DEAD ||
17614bff34e3Sthurlow 	    odvp->v_vfsp->vfs_flag & VFS_UNMOUNTED ||
17624bff34e3Sthurlow 	    ndvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
17634bff34e3Sthurlow 		return (EIO);
17644bff34e3Sthurlow 
17654bff34e3Sthurlow 	return (smbfsrename(odvp, onm, ndvp, nnm, cr, ct));
17664bff34e3Sthurlow }
17674bff34e3Sthurlow 
17684bff34e3Sthurlow /*
17694bff34e3Sthurlow  * smbfsrename does the real work of renaming in SMBFS
17704bff34e3Sthurlow  */
17714bff34e3Sthurlow /* ARGSUSED */
17724bff34e3Sthurlow static int
17734bff34e3Sthurlow smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
17744bff34e3Sthurlow 	caller_context_t *ct)
17754bff34e3Sthurlow {
17764bff34e3Sthurlow 	int		error;
17774bff34e3Sthurlow 	int		nvp_locked = 0;
17784bff34e3Sthurlow 	vnode_t		*nvp = NULL;
17794bff34e3Sthurlow 	vnode_t		*ovp = NULL;
17804bff34e3Sthurlow 	smbnode_t	*onp;
17814bff34e3Sthurlow 	smbnode_t	*odnp;
17824bff34e3Sthurlow 	smbnode_t	*ndnp;
17834bff34e3Sthurlow 	struct smb_cred	scred;
17844bff34e3Sthurlow 	/* enum smbfsstat	status; */
17854bff34e3Sthurlow 
17864bff34e3Sthurlow 	ASSERT(curproc->p_zone == VTOSMI(odvp)->smi_zone);
17874bff34e3Sthurlow 
17884bff34e3Sthurlow 	if (strcmp(onm, ".") == 0 || strcmp(onm, "..") == 0 ||
17894bff34e3Sthurlow 	    strcmp(nnm, ".") == 0 || strcmp(nnm, "..") == 0)
17904bff34e3Sthurlow 		return (EINVAL);
17914bff34e3Sthurlow 
17924bff34e3Sthurlow 	/*
17934bff34e3Sthurlow 	 * Check that everything is on the same filesystem.
17944bff34e3Sthurlow 	 * vn_rename checks the fsid's, but in case we don't
17954bff34e3Sthurlow 	 * fill those in correctly, check here too.
17964bff34e3Sthurlow 	 */
17974bff34e3Sthurlow 	if (odvp->v_vfsp != ndvp->v_vfsp)
17984bff34e3Sthurlow 		return (EXDEV);
17994bff34e3Sthurlow 
18004bff34e3Sthurlow 	odnp = VTOSMB(odvp);
18014bff34e3Sthurlow 	ndnp = VTOSMB(ndvp);
18024bff34e3Sthurlow 
18034bff34e3Sthurlow 	/*
18044bff34e3Sthurlow 	 * Avoid deadlock here on old vs new directory nodes
18054bff34e3Sthurlow 	 * by always taking the locks in order of address.
18064bff34e3Sthurlow 	 * The order is arbitrary, but must be consistent.
18074bff34e3Sthurlow 	 */
18084bff34e3Sthurlow 	if (odnp < ndnp) {
18094bff34e3Sthurlow 		if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER,
18104bff34e3Sthurlow 		    SMBINTR(odvp)))
18114bff34e3Sthurlow 			return (EINTR);
18124bff34e3Sthurlow 		if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER,
18134bff34e3Sthurlow 		    SMBINTR(ndvp))) {
18144bff34e3Sthurlow 			smbfs_rw_exit(&odnp->r_rwlock);
18154bff34e3Sthurlow 			return (EINTR);
18164bff34e3Sthurlow 		}
18174bff34e3Sthurlow 	} else {
18184bff34e3Sthurlow 		if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER,
18194bff34e3Sthurlow 		    SMBINTR(ndvp)))
18204bff34e3Sthurlow 			return (EINTR);
18214bff34e3Sthurlow 		if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER,
18224bff34e3Sthurlow 		    SMBINTR(odvp))) {
18234bff34e3Sthurlow 			smbfs_rw_exit(&ndnp->r_rwlock);
18244bff34e3Sthurlow 			return (EINTR);
18254bff34e3Sthurlow 		}
18264bff34e3Sthurlow 	}
18274bff34e3Sthurlow 	/*
18284bff34e3Sthurlow 	 * No returns after this point (goto out)
18294bff34e3Sthurlow 	 */
18304bff34e3Sthurlow 
18314bff34e3Sthurlow 	/*
18324bff34e3Sthurlow 	 * Need write access on source and target.
18334bff34e3Sthurlow 	 * Server takes care of most checks.
18344bff34e3Sthurlow 	 */
18354bff34e3Sthurlow 	error = smbfs_access(odvp, VWRITE|VEXEC, 0, cr, ct);
18364bff34e3Sthurlow 	if (error)
18374bff34e3Sthurlow 		goto out;
18384bff34e3Sthurlow 	if (odvp != ndvp) {
18394bff34e3Sthurlow 		error = smbfs_access(ndvp, VWRITE, 0, cr, ct);
18404bff34e3Sthurlow 		if (error)
18414bff34e3Sthurlow 			goto out;
18424bff34e3Sthurlow 	}
18434bff34e3Sthurlow 
18444bff34e3Sthurlow 	/*
18454bff34e3Sthurlow 	 * Lookup the source name.  Must already exist.
18464bff34e3Sthurlow 	 */
18474bff34e3Sthurlow 	error = smbfslookup(odvp, onm, &ovp, cr, 0, ct);
18484bff34e3Sthurlow 	if (error)
18494bff34e3Sthurlow 		goto out;
18504bff34e3Sthurlow 
18514bff34e3Sthurlow 	/*
18524bff34e3Sthurlow 	 * Lookup the target file.  If it exists, it needs to be
18534bff34e3Sthurlow 	 * checked to see whether it is a mount point and whether
18544bff34e3Sthurlow 	 * it is active (open).
18554bff34e3Sthurlow 	 */
18564bff34e3Sthurlow 	error = smbfslookup(ndvp, nnm, &nvp, cr, 0, ct);
18574bff34e3Sthurlow 	if (!error) {
18584bff34e3Sthurlow 		/*
18594bff34e3Sthurlow 		 * Target (nvp) already exists.  Check that it
18604bff34e3Sthurlow 		 * has the same type as the source.  The server
18614bff34e3Sthurlow 		 * will check this also, (and more reliably) but
18624bff34e3Sthurlow 		 * this lets us return the correct error codes.
18634bff34e3Sthurlow 		 */
18644bff34e3Sthurlow 		if (ovp->v_type == VDIR) {
18654bff34e3Sthurlow 			if (nvp->v_type != VDIR) {
18664bff34e3Sthurlow 				error = ENOTDIR;
18674bff34e3Sthurlow 				goto out;
18684bff34e3Sthurlow 			}
18694bff34e3Sthurlow 		} else {
18704bff34e3Sthurlow 			if (nvp->v_type == VDIR) {
18714bff34e3Sthurlow 				error = EISDIR;
18724bff34e3Sthurlow 				goto out;
18734bff34e3Sthurlow 			}
18744bff34e3Sthurlow 		}
18754bff34e3Sthurlow 
18764bff34e3Sthurlow 		/*
18774bff34e3Sthurlow 		 * POSIX dictates that when the source and target
18784bff34e3Sthurlow 		 * entries refer to the same file object, rename
18794bff34e3Sthurlow 		 * must do nothing and exit without error.
18804bff34e3Sthurlow 		 */
18814bff34e3Sthurlow 		if (ovp == nvp) {
18824bff34e3Sthurlow 			error = 0;
18834bff34e3Sthurlow 			goto out;
18844bff34e3Sthurlow 		}
18854bff34e3Sthurlow 
18864bff34e3Sthurlow 		/*
18874bff34e3Sthurlow 		 * Also must ensure the target is not a mount point,
18884bff34e3Sthurlow 		 * and keep mount/umount away until we're done.
18894bff34e3Sthurlow 		 */
18904bff34e3Sthurlow 		if (vn_vfsrlock(nvp)) {
18914bff34e3Sthurlow 			error = EBUSY;
18924bff34e3Sthurlow 			goto out;
18934bff34e3Sthurlow 		}
18944bff34e3Sthurlow 		nvp_locked = 1;
18954bff34e3Sthurlow 		if (vn_mountedvfs(nvp) != NULL) {
18964bff34e3Sthurlow 			error = EBUSY;
18974bff34e3Sthurlow 			goto out;
18984bff34e3Sthurlow 		}
18994bff34e3Sthurlow 
19004bff34e3Sthurlow #ifdef NOT_YET
19014bff34e3Sthurlow 		/*
19024bff34e3Sthurlow 		 * Purge the name cache of all references to this vnode
19034bff34e3Sthurlow 		 * so that we can check the reference count to infer
19044bff34e3Sthurlow 		 * whether it is active or not.
19054bff34e3Sthurlow 		 */
19064bff34e3Sthurlow 		/*
19074bff34e3Sthurlow 		 * First just remove the entry from the name cache, as it
19084bff34e3Sthurlow 		 * is most likely the only entry for this vp.
19094bff34e3Sthurlow 		 */
19104bff34e3Sthurlow 		dnlc_remove(ndvp, nnm);
19114bff34e3Sthurlow 		/*
19124bff34e3Sthurlow 		 * If the file has a v_count > 1 then there may be more
19134bff34e3Sthurlow 		 * than one entry in the name cache due multiple links
19144bff34e3Sthurlow 		 * or an open file, but we don't have the real reference
19154bff34e3Sthurlow 		 * count so flush all possible entries.
19164bff34e3Sthurlow 		 */
19174bff34e3Sthurlow 		if (nvp->v_count > 1)
19184bff34e3Sthurlow 			dnlc_purge_vp(nvp);
19194bff34e3Sthurlow #endif
19204bff34e3Sthurlow 
19214bff34e3Sthurlow 		if (nvp->v_count > 1 && nvp->v_type != VDIR) {
19224bff34e3Sthurlow 			/*
19234bff34e3Sthurlow 			 * The target file exists, is not the same as
19244bff34e3Sthurlow 			 * the source file, and is active.  Other FS
19254bff34e3Sthurlow 			 * implementations unlink the target here.
19264bff34e3Sthurlow 			 * For SMB, we don't assume we can remove an
19274bff34e3Sthurlow 			 * open file.  Return an error instead.
19284bff34e3Sthurlow 			 * Darwin returned an error here too.
19294bff34e3Sthurlow 			 */
19304bff34e3Sthurlow 			error = EEXIST;
19314bff34e3Sthurlow 			goto out;
19324bff34e3Sthurlow 		}
19334bff34e3Sthurlow 	} /* nvp */
19344bff34e3Sthurlow 
19354bff34e3Sthurlow #ifdef NOT_YET
19364bff34e3Sthurlow 	dnlc_remove(odvp, onm);
19374bff34e3Sthurlow 	dnlc_remove(ndvp, nnm);
19384bff34e3Sthurlow #endif
19394bff34e3Sthurlow 
19404bff34e3Sthurlow 	onp = VTOSMB(ovp);
19414bff34e3Sthurlow 	smb_credinit(&scred, curproc, cr);
19424bff34e3Sthurlow 	error = smbfs_smb_rename(onp, ndnp, nnm, strlen(nnm), &scred);
19434bff34e3Sthurlow 	smb_credrele(&scred);
19444bff34e3Sthurlow 
19454bff34e3Sthurlow 
19464bff34e3Sthurlow out:
19474bff34e3Sthurlow 	if (nvp) {
19484bff34e3Sthurlow 		if (nvp_locked)
19494bff34e3Sthurlow 			vn_vfsunlock(nvp);
19504bff34e3Sthurlow 		VN_RELE(nvp);
19514bff34e3Sthurlow 	}
19524bff34e3Sthurlow 	if (ovp)
19534bff34e3Sthurlow 		VN_RELE(ovp);
19544bff34e3Sthurlow 
19554bff34e3Sthurlow 	smbfs_rw_exit(&odnp->r_rwlock);
19564bff34e3Sthurlow 	smbfs_rw_exit(&ndnp->r_rwlock);
19574bff34e3Sthurlow 
19584bff34e3Sthurlow 	return (error);
19594bff34e3Sthurlow }
19604bff34e3Sthurlow 
19614bff34e3Sthurlow /*
19624bff34e3Sthurlow  * XXX
19634bff34e3Sthurlow  * vsecattr_t is new to build 77, and we need to eventually support
19644bff34e3Sthurlow  * it in order to create an ACL when an object is created.
19654bff34e3Sthurlow  *
19664bff34e3Sthurlow  * This op should support the new FIGNORECASE flag for case-insensitive
19674bff34e3Sthurlow  * lookups, per PSARC 2007/244.
19684bff34e3Sthurlow  */
19694bff34e3Sthurlow /* ARGSUSED */
19704bff34e3Sthurlow static int
19714bff34e3Sthurlow smbfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp,
19724bff34e3Sthurlow 	cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp)
19734bff34e3Sthurlow {
19744bff34e3Sthurlow 	vnode_t		*vp;
19754bff34e3Sthurlow 	struct smbnode	*dnp = VTOSMB(dvp);
19764bff34e3Sthurlow 	struct smbmntinfo *smi = VTOSMI(dvp);
19774bff34e3Sthurlow 	struct smb_cred	scred;
19784bff34e3Sthurlow 	struct smbfattr	fattr;
19794bff34e3Sthurlow 	const char		*name = (const char *) nm;
19804bff34e3Sthurlow 	int		nmlen = strlen(name);
19814bff34e3Sthurlow 	int		error, hiderr;
19824bff34e3Sthurlow 
19834bff34e3Sthurlow 	if (curproc->p_zone != smi->smi_zone)
19844bff34e3Sthurlow 		return (EPERM);
19854bff34e3Sthurlow 
19864bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
19874bff34e3Sthurlow 		return (EIO);
19884bff34e3Sthurlow 
19894bff34e3Sthurlow 	if ((nmlen == 1 && name[0] == '.') ||
19904bff34e3Sthurlow 	    (nmlen == 2 && name[0] == '.' && name[1] == '.'))
19914bff34e3Sthurlow 		return (EEXIST);
19924bff34e3Sthurlow 
19934bff34e3Sthurlow 	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
19944bff34e3Sthurlow 		return (EINTR);
19954bff34e3Sthurlow 	smb_credinit(&scred, curproc, cr);
19964bff34e3Sthurlow 
19974bff34e3Sthurlow 	/*
19984bff34e3Sthurlow 	 * XXX: Do we need r_lkserlock too?
19994bff34e3Sthurlow 	 * No use of any shared fid or fctx...
20004bff34e3Sthurlow 	 */
20014bff34e3Sthurlow 
20024bff34e3Sthurlow 	/*
20034bff34e3Sthurlow 	 * Require write access in the containing directory.
20044bff34e3Sthurlow 	 */
20054bff34e3Sthurlow 	error = smbfs_access(dvp, VWRITE, 0, cr, ct);
20064bff34e3Sthurlow 	if (error)
20074bff34e3Sthurlow 		goto out;
20084bff34e3Sthurlow 
20094bff34e3Sthurlow 	error = smbfs_smb_mkdir(dnp, name, nmlen, &scred);
20104bff34e3Sthurlow 	if (error)
20114bff34e3Sthurlow 		goto out;
20124bff34e3Sthurlow 
20134bff34e3Sthurlow 	error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred);
20144bff34e3Sthurlow 	if (error)
20154bff34e3Sthurlow 		goto out;
20164bff34e3Sthurlow 
20174bff34e3Sthurlow 	smbfs_attr_touchdir(dnp);
20184bff34e3Sthurlow 
20194bff34e3Sthurlow 	error = smbfs_nget(dvp, name, nmlen, &fattr, &vp);
20204bff34e3Sthurlow 	if (error)
20214bff34e3Sthurlow 		goto out;
20224bff34e3Sthurlow 
20234bff34e3Sthurlow #ifdef NOT_YET
20244bff34e3Sthurlow 	dnlc_update(dvp, name, vp);
20254bff34e3Sthurlow #endif
20264bff34e3Sthurlow 
20274bff34e3Sthurlow 	if (name[0] == '.')
20284bff34e3Sthurlow 		if ((hiderr = smbfs_smb_hideit(VTOSMB(vp), NULL, 0, &scred)))
20294bff34e3Sthurlow 			SMBVDEBUG("hide failure %d\n", hiderr);
20304bff34e3Sthurlow 
20314bff34e3Sthurlow 	/* Success! */
20324bff34e3Sthurlow 	*vpp = vp;
20334bff34e3Sthurlow 	error = 0;
20344bff34e3Sthurlow out:
20354bff34e3Sthurlow 	smb_credrele(&scred);
20364bff34e3Sthurlow 	smbfs_rw_exit(&dnp->r_rwlock);
20374bff34e3Sthurlow 
20384bff34e3Sthurlow 	if (name != nm)
20394bff34e3Sthurlow 		smbfs_name_free(name, nmlen);
20404bff34e3Sthurlow 
20414bff34e3Sthurlow 	return (error);
20424bff34e3Sthurlow }
20434bff34e3Sthurlow 
20444bff34e3Sthurlow /*
20454bff34e3Sthurlow  * XXX
20464bff34e3Sthurlow  * This op should support the new FIGNORECASE flag for case-insensitive
20474bff34e3Sthurlow  * lookups, per PSARC 2007/244.
20484bff34e3Sthurlow  */
20494bff34e3Sthurlow /* ARGSUSED */
20504bff34e3Sthurlow static int
20514bff34e3Sthurlow smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
20524bff34e3Sthurlow 	caller_context_t *ct, int flags)
20534bff34e3Sthurlow {
20544bff34e3Sthurlow 	vnode_t		*vp = NULL;
20554bff34e3Sthurlow 	int		vp_locked = 0;
20564bff34e3Sthurlow 	struct smbmntinfo *smi = VTOSMI(dvp);
20574bff34e3Sthurlow 	struct smbnode	*dnp = VTOSMB(dvp);
20584bff34e3Sthurlow 	struct smbnode	*np;
20594bff34e3Sthurlow 	struct smb_cred	scred;
20604bff34e3Sthurlow 	int		error;
20614bff34e3Sthurlow 
20624bff34e3Sthurlow 	if (curproc->p_zone != smi->smi_zone)
20634bff34e3Sthurlow 		return (EPERM);
20644bff34e3Sthurlow 
20654bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
20664bff34e3Sthurlow 		return (EIO);
20674bff34e3Sthurlow 
20684bff34e3Sthurlow 	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
20694bff34e3Sthurlow 		return (EINTR);
20704bff34e3Sthurlow 	smb_credinit(&scred, curproc, cr);
20714bff34e3Sthurlow 
20724bff34e3Sthurlow 	/*
20734bff34e3Sthurlow 	 * Require w/x access in the containing directory.
20744bff34e3Sthurlow 	 * Server handles all other access checks.
20754bff34e3Sthurlow 	 */
20764bff34e3Sthurlow 	error = smbfs_access(dvp, VEXEC|VWRITE, 0, cr, ct);
20774bff34e3Sthurlow 	if (error)
20784bff34e3Sthurlow 		goto out;
20794bff34e3Sthurlow 
20804bff34e3Sthurlow 	/*
20814bff34e3Sthurlow 	 * First lookup the entry to be removed.
20824bff34e3Sthurlow 	 */
20834bff34e3Sthurlow 	error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
20844bff34e3Sthurlow 	if (error)
20854bff34e3Sthurlow 		goto out;
20864bff34e3Sthurlow 	np = VTOSMB(vp);
20874bff34e3Sthurlow 
20884bff34e3Sthurlow 	/*
20894bff34e3Sthurlow 	 * Disallow rmdir of "." or current dir, or the FS root.
20904bff34e3Sthurlow 	 * Also make sure it's a directory, not a mount point,
20914bff34e3Sthurlow 	 * and lock to keep mount/umount away until we're done.
20924bff34e3Sthurlow 	 */
20934bff34e3Sthurlow 	if ((vp == dvp) || (vp == cdir) || (vp->v_flag & VROOT)) {
20944bff34e3Sthurlow 		error = EINVAL;
20954bff34e3Sthurlow 		goto out;
20964bff34e3Sthurlow 	}
20974bff34e3Sthurlow 	if (vp->v_type != VDIR) {
20984bff34e3Sthurlow 		error = ENOTDIR;
20994bff34e3Sthurlow 		goto out;
21004bff34e3Sthurlow 	}
21014bff34e3Sthurlow 	if (vn_vfsrlock(vp)) {
21024bff34e3Sthurlow 		error = EBUSY;
21034bff34e3Sthurlow 		goto out;
21044bff34e3Sthurlow 	}
21054bff34e3Sthurlow 	vp_locked = 1;
21064bff34e3Sthurlow 	if (vn_mountedvfs(vp) != NULL) {
21074bff34e3Sthurlow 		error = EBUSY;
21084bff34e3Sthurlow 		goto out;
21094bff34e3Sthurlow 	}
21104bff34e3Sthurlow 
21114bff34e3Sthurlow 	error = smbfs_smb_rmdir(np, &scred);
21124bff34e3Sthurlow 	if (error)
21134bff34e3Sthurlow 		goto out;
21144bff34e3Sthurlow 
21154bff34e3Sthurlow 	mutex_enter(&np->r_statelock);
21164bff34e3Sthurlow 	dnp->n_flag |= NMODIFIED;
21174bff34e3Sthurlow 	mutex_exit(&np->r_statelock);
21184bff34e3Sthurlow 	smbfs_attr_touchdir(dnp);
21194bff34e3Sthurlow #ifdef NOT_YET
21204bff34e3Sthurlow 	dnlc_remove(dvp, nm);
21214bff34e3Sthurlow 	dnlc_purge_vp(vp);
21224bff34e3Sthurlow #endif
21234bff34e3Sthurlow 	smb_rmhash(np);
21244bff34e3Sthurlow 
21254bff34e3Sthurlow out:
21264bff34e3Sthurlow 	if (vp) {
21274bff34e3Sthurlow 		if (vp_locked)
21284bff34e3Sthurlow 			vn_vfsunlock(vp);
21294bff34e3Sthurlow 		VN_RELE(vp);
21304bff34e3Sthurlow 	}
21314bff34e3Sthurlow 	smb_credrele(&scred);
21324bff34e3Sthurlow 	smbfs_rw_exit(&dnp->r_rwlock);
21334bff34e3Sthurlow 
21344bff34e3Sthurlow 	return (error);
21354bff34e3Sthurlow }
21364bff34e3Sthurlow 
21374bff34e3Sthurlow 
21384bff34e3Sthurlow /* ARGSUSED */
21394bff34e3Sthurlow static int
21404bff34e3Sthurlow smbfs_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp,
21414bff34e3Sthurlow 	caller_context_t *ct, int flags)
21424bff34e3Sthurlow {
21434bff34e3Sthurlow 	struct smbnode	*np = VTOSMB(vp);
21444bff34e3Sthurlow 	int		error = 0;
21454bff34e3Sthurlow 	smbmntinfo_t	*smi;
21464bff34e3Sthurlow 
21474bff34e3Sthurlow 	smi = VTOSMI(vp);
21484bff34e3Sthurlow 
21494bff34e3Sthurlow 	if (curproc->p_zone != smi->smi_zone)
21504bff34e3Sthurlow 		return (EIO);
21514bff34e3Sthurlow 
21524bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
21534bff34e3Sthurlow 		return (EIO);
21544bff34e3Sthurlow 
21554bff34e3Sthurlow 	/*
21564bff34e3Sthurlow 	 * Require read access in the directory.
21574bff34e3Sthurlow 	 */
21584bff34e3Sthurlow 	error = smbfs_access(vp, VREAD, 0, cr, ct);
21594bff34e3Sthurlow 	if (error)
21604bff34e3Sthurlow 		return (error);
21614bff34e3Sthurlow 
21624bff34e3Sthurlow 	ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER));
21634bff34e3Sthurlow 
21644bff34e3Sthurlow 	/*
21654bff34e3Sthurlow 	 * XXX: Todo readdir cache here
21664bff34e3Sthurlow 	 * Note: NFS code is just below this.
21674bff34e3Sthurlow 	 *
21684bff34e3Sthurlow 	 * I am serializing the entire readdir opreation
21694bff34e3Sthurlow 	 * now since we have not yet implemented readdir
21704bff34e3Sthurlow 	 * cache. This fix needs to be revisited once
21714bff34e3Sthurlow 	 * we implement readdir cache.
21724bff34e3Sthurlow 	 */
21734bff34e3Sthurlow 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp)))
21744bff34e3Sthurlow 		return (EINTR);
21754bff34e3Sthurlow 
21764bff34e3Sthurlow 	error = smbfs_readvdir(vp, uiop, cr, eofp, ct);
21774bff34e3Sthurlow 
21784bff34e3Sthurlow 	smbfs_rw_exit(&np->r_lkserlock);
21794bff34e3Sthurlow 
21804bff34e3Sthurlow 	return (error);
21814bff34e3Sthurlow }
21824bff34e3Sthurlow 
21834bff34e3Sthurlow /* ARGSUSED */
21844bff34e3Sthurlow static int
21854bff34e3Sthurlow smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
21864bff34e3Sthurlow 	caller_context_t *ct)
21874bff34e3Sthurlow {
21884bff34e3Sthurlow 	size_t		dbufsiz;
21894bff34e3Sthurlow 	struct dirent64 *dp;
21904bff34e3Sthurlow 	struct smb_cred scred;
21914bff34e3Sthurlow 	vnode_t		*newvp;
21924bff34e3Sthurlow 	struct smbnode	*np = VTOSMB(vp);
21934bff34e3Sthurlow 	int		nmlen, reclen, error = 0;
21944bff34e3Sthurlow 	long		offset, limit;
21954bff34e3Sthurlow 	struct smbfs_fctx *ctx;
21964bff34e3Sthurlow 
21974bff34e3Sthurlow 	ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone);
21984bff34e3Sthurlow 
21994bff34e3Sthurlow 	/* Make sure we serialize for n_dirseq use. */
22004bff34e3Sthurlow 	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_WRITER));
22014bff34e3Sthurlow 
22024bff34e3Sthurlow 	/* Min size is DIRENT64_RECLEN(256) rounded up. */
22034bff34e3Sthurlow 	if (uio->uio_resid < 512 || uio->uio_offset < 0)
22044bff34e3Sthurlow 		return (EINVAL);
22054bff34e3Sthurlow 
22064bff34e3Sthurlow 	/*
22074bff34e3Sthurlow 	 * This dnlc_purge_vp ensures that name cache for this dir will be
22084bff34e3Sthurlow 	 * current - it'll only have the items for which the smbfs_nget
22094bff34e3Sthurlow 	 * MAKEENTRY happened.
22104bff34e3Sthurlow 	 */
22114bff34e3Sthurlow #ifdef NOT_YET
22124bff34e3Sthurlow 	if (smbfs_fastlookup)
22134bff34e3Sthurlow 		dnlc_purge_vp(vp);
22144bff34e3Sthurlow #endif
22154bff34e3Sthurlow 	SMBVDEBUG("dirname='%s'\n", np->n_rpath);
22164bff34e3Sthurlow 	smb_credinit(&scred, curproc, cr);
22174bff34e3Sthurlow 	dbufsiz = DIRENT64_RECLEN(MAXNAMELEN);
22184bff34e3Sthurlow 	dp = kmem_alloc(dbufsiz, KM_SLEEP);
22194bff34e3Sthurlow 
22204bff34e3Sthurlow 	offset = uio->uio_offset; /* NB: "cookie" */
22214bff34e3Sthurlow 	limit = uio->uio_resid / DIRENT64_RECLEN(1);
22224bff34e3Sthurlow 	SMBVDEBUG("offset=0x%ld, limit=0x%ld\n", offset, limit);
22234bff34e3Sthurlow 
22244bff34e3Sthurlow 	if (offset == 0) {
22254bff34e3Sthurlow 		/* Don't know EOF until findclose */
22264bff34e3Sthurlow 		np->n_direof = -1;
22274bff34e3Sthurlow 	} else if (offset == np->n_direof) {
22284bff34e3Sthurlow 		/* Arrived at end of directory. */
22294bff34e3Sthurlow 		goto out;
22304bff34e3Sthurlow 	}
22314bff34e3Sthurlow 
22324bff34e3Sthurlow 	/*
22334bff34e3Sthurlow 	 * Generate the "." and ".." entries here so we can
22344bff34e3Sthurlow 	 * (1) make sure they appear (but only once), and
22354bff34e3Sthurlow 	 * (2) deal with getting their I numbers which the
22364bff34e3Sthurlow 	 * findnext below does only for normal names.
22374bff34e3Sthurlow 	 */
22384bff34e3Sthurlow 	while (limit && offset < 2) {
22394bff34e3Sthurlow 		limit--;
22404bff34e3Sthurlow 		reclen = DIRENT64_RECLEN(offset + 1);
22414bff34e3Sthurlow 		bzero(dp, reclen);
22424bff34e3Sthurlow 		/*LINTED*/
22434bff34e3Sthurlow 		dp->d_reclen = reclen;
22444bff34e3Sthurlow 		/* Tricky: offset 0 is ".", offset 1 is ".." */
22454bff34e3Sthurlow 		dp->d_name[0] = '.';
22464bff34e3Sthurlow 		dp->d_name[1] = '.';
22474bff34e3Sthurlow 		dp->d_name[offset + 1] = '\0';
22484bff34e3Sthurlow 		/*
22494bff34e3Sthurlow 		 * Want the real I-numbers for the "." and ".."
22504bff34e3Sthurlow 		 * entries.  For these two names, we know that
22514bff34e3Sthurlow 		 * smbfslookup can do this all locally.
22524bff34e3Sthurlow 		 */
22534bff34e3Sthurlow 		error = smbfslookup(vp, dp->d_name, &newvp, cr, 1, ct);
22544bff34e3Sthurlow 		if (error) {
22554bff34e3Sthurlow 			dp->d_ino = np->n_ino + offset; /* fiction */
22564bff34e3Sthurlow 		} else {
22574bff34e3Sthurlow 			dp->d_ino = VTOSMB(newvp)->n_ino;
22584bff34e3Sthurlow 			VN_RELE(newvp);
22594bff34e3Sthurlow 		}
22604bff34e3Sthurlow 		dp->d_off = offset + 1;  /* see d_off below */
22614bff34e3Sthurlow 		error = uiomove(dp, dp->d_reclen, UIO_READ, uio);
22624bff34e3Sthurlow 		if (error)
22634bff34e3Sthurlow 			goto out;
22644bff34e3Sthurlow 		uio->uio_offset = ++offset;
22654bff34e3Sthurlow 	}
22664bff34e3Sthurlow 	if (limit == 0)
22674bff34e3Sthurlow 		goto out;
22684bff34e3Sthurlow 	if (offset != np->n_dirofs || np->n_dirseq == NULL) {
22694bff34e3Sthurlow 		SMBVDEBUG("Reopening search %ld:%ld\n", offset, np->n_dirofs);
22704bff34e3Sthurlow 		if (np->n_dirseq) {
22714bff34e3Sthurlow 			(void) smbfs_smb_findclose(np->n_dirseq, &scred);
22724bff34e3Sthurlow 			np->n_dirseq = NULL;
22734bff34e3Sthurlow 		}
22744bff34e3Sthurlow 		np->n_dirofs = 2;
22754bff34e3Sthurlow 		error = smbfs_smb_findopen(np, "*", 1,
22764bff34e3Sthurlow 		    SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR,
22774bff34e3Sthurlow 		    &scred, &ctx);
22784bff34e3Sthurlow 		if (error) {
22794bff34e3Sthurlow 			SMBVDEBUG("can not open search, error = %d", error);
22804bff34e3Sthurlow 			goto out;
22814bff34e3Sthurlow 		}
22824bff34e3Sthurlow 		np->n_dirseq = ctx;
22834bff34e3Sthurlow 	} else
22844bff34e3Sthurlow 		ctx = np->n_dirseq;
22854bff34e3Sthurlow 	while (np->n_dirofs < offset) {
22864bff34e3Sthurlow 		if (smbfs_smb_findnext(ctx, offset - np->n_dirofs++,
22874bff34e3Sthurlow 		    &scred) != 0) {
22884bff34e3Sthurlow 			(void) smbfs_smb_findclose(np->n_dirseq, &scred);
22894bff34e3Sthurlow 			np->n_dirseq = NULL;
22904bff34e3Sthurlow 			np->n_direof = np->n_dirofs;
22914bff34e3Sthurlow 			np->n_dirofs = 0;
22924bff34e3Sthurlow 			*eofp = 1;
22934bff34e3Sthurlow 			error = 0;
22944bff34e3Sthurlow 			goto out;
22954bff34e3Sthurlow 		}
22964bff34e3Sthurlow 	}
22974bff34e3Sthurlow 	error = 0;
22984bff34e3Sthurlow 	for (; limit; limit--) {
22994bff34e3Sthurlow 		error = smbfs_smb_findnext(ctx, limit, &scred);
23004bff34e3Sthurlow 		if (error) {
23014bff34e3Sthurlow 			if (error == EBADRPC)
23024bff34e3Sthurlow 				error = ENOENT;
23034bff34e3Sthurlow 			(void) smbfs_smb_findclose(np->n_dirseq, &scred);
23044bff34e3Sthurlow 			np->n_dirseq = NULL;
23054bff34e3Sthurlow 			np->n_direof = np->n_dirofs;
23064bff34e3Sthurlow 			np->n_dirofs = 0;
23074bff34e3Sthurlow 			*eofp = 1;
23084bff34e3Sthurlow 			error = 0;
23094bff34e3Sthurlow 			break;
23104bff34e3Sthurlow 		}
23114bff34e3Sthurlow 		np->n_dirofs++;
23124bff34e3Sthurlow 		/* Sanity check the name length. */
23134bff34e3Sthurlow 		nmlen = ctx->f_nmlen;
23144bff34e3Sthurlow 		if (nmlen > (MAXNAMELEN - 1)) {
23154bff34e3Sthurlow 			nmlen = MAXNAMELEN - 1;
23164bff34e3Sthurlow 			SMBVDEBUG("Truncating name: %s\n", ctx->f_name);
23174bff34e3Sthurlow 		}
23184bff34e3Sthurlow 		reclen = DIRENT64_RECLEN(nmlen);
23194bff34e3Sthurlow 		if (uio->uio_resid < reclen)
23204bff34e3Sthurlow 			break;
23214bff34e3Sthurlow 		bzero(dp, reclen);
23224bff34e3Sthurlow 		/*LINTED*/
23234bff34e3Sthurlow 		dp->d_reclen = reclen;
23244bff34e3Sthurlow 		dp->d_ino = ctx->f_attr.fa_ino;
23254bff34e3Sthurlow 		/*
23264bff34e3Sthurlow 		 * Note: d_off is the offset that a user-level program
23274bff34e3Sthurlow 		 * should seek to for reading the _next_ directory entry.
23284bff34e3Sthurlow 		 * See libc: readdir, telldir, seekdir
23294bff34e3Sthurlow 		 */
23304bff34e3Sthurlow 		dp->d_off = offset + 1;
23314bff34e3Sthurlow 		bcopy(ctx->f_name, dp->d_name, nmlen);
23324bff34e3Sthurlow 		dp->d_name[nmlen] = '\0';
23334bff34e3Sthurlow #ifdef NOT_YET
23344bff34e3Sthurlow 		if (smbfs_fastlookup) {
23354bff34e3Sthurlow 			if (smbfs_nget(vp, ctx->f_name,
23364bff34e3Sthurlow 			    ctx->f_nmlen, &ctx->f_attr, &newvp) == 0)
23374bff34e3Sthurlow 				VN_RELE(newvp);
23384bff34e3Sthurlow 		}
23394bff34e3Sthurlow #endif /* NOT_YET */
23404bff34e3Sthurlow 		error = uiomove(dp, dp->d_reclen, UIO_READ, uio);
23414bff34e3Sthurlow 		if (error)
23424bff34e3Sthurlow 			break;
23434bff34e3Sthurlow 		uio->uio_offset = ++offset;
23444bff34e3Sthurlow 	}
23454bff34e3Sthurlow 	if (error == ENOENT)
23464bff34e3Sthurlow 		error = 0;
23474bff34e3Sthurlow out:
23484bff34e3Sthurlow 	kmem_free(dp, dbufsiz);
23494bff34e3Sthurlow 	smb_credrele(&scred);
23504bff34e3Sthurlow 	return (error);
23514bff34e3Sthurlow }
23524bff34e3Sthurlow 
23534bff34e3Sthurlow 
23544bff34e3Sthurlow /*
23554bff34e3Sthurlow  * The pair of functions VOP_RWLOCK, VOP_RWUNLOCK
23564bff34e3Sthurlow  * are optional functions that are called by:
23574bff34e3Sthurlow  *    getdents, before/after VOP_READDIR
23584bff34e3Sthurlow  *    pread, before/after ... VOP_READ
23594bff34e3Sthurlow  *    pwrite, before/after ... VOP_WRITE
23604bff34e3Sthurlow  *    (other places)
23614bff34e3Sthurlow  *
23624bff34e3Sthurlow  * Careful here: None of the above check for any
23634bff34e3Sthurlow  * error returns from VOP_RWLOCK / VOP_RWUNLOCK!
23644bff34e3Sthurlow  * In fact, the return value from _rwlock is NOT
23654bff34e3Sthurlow  * an error code, but V_WRITELOCK_TRUE / _FALSE.
23664bff34e3Sthurlow  *
23674bff34e3Sthurlow  * Therefore, it's up to _this_ code to make sure
23684bff34e3Sthurlow  * the lock state remains balanced, which means
23694bff34e3Sthurlow  * we can't "bail out" on interrupts, etc.
23704bff34e3Sthurlow  */
23714bff34e3Sthurlow 
23724bff34e3Sthurlow /* ARGSUSED2 */
23734bff34e3Sthurlow static int
23744bff34e3Sthurlow smbfs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
23754bff34e3Sthurlow {
23764bff34e3Sthurlow 	smbnode_t	*np = VTOSMB(vp);
23774bff34e3Sthurlow 
23784bff34e3Sthurlow 	if (!write_lock) {
23794bff34e3Sthurlow 		(void) smbfs_rw_enter_sig(&np->r_rwlock, RW_READER, FALSE);
23804bff34e3Sthurlow 		return (V_WRITELOCK_FALSE);
23814bff34e3Sthurlow 	}
23824bff34e3Sthurlow 
23834bff34e3Sthurlow 
23844bff34e3Sthurlow 	(void) smbfs_rw_enter_sig(&np->r_rwlock, RW_WRITER, FALSE);
23854bff34e3Sthurlow 	return (V_WRITELOCK_TRUE);
23864bff34e3Sthurlow }
23874bff34e3Sthurlow 
23884bff34e3Sthurlow /* ARGSUSED */
23894bff34e3Sthurlow static void
23904bff34e3Sthurlow smbfs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
23914bff34e3Sthurlow {
23924bff34e3Sthurlow 	smbnode_t	*np = VTOSMB(vp);
23934bff34e3Sthurlow 
23944bff34e3Sthurlow 	smbfs_rw_exit(&np->r_rwlock);
23954bff34e3Sthurlow }
23964bff34e3Sthurlow 
23974bff34e3Sthurlow 
23984bff34e3Sthurlow /* ARGSUSED */
23994bff34e3Sthurlow static int
24004bff34e3Sthurlow smbfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
24014bff34e3Sthurlow {
24024bff34e3Sthurlow 	smbmntinfo_t	*smi;
24034bff34e3Sthurlow 
24044bff34e3Sthurlow 	smi = VTOSMI(vp);
24054bff34e3Sthurlow 
24064bff34e3Sthurlow 	if (curproc->p_zone != smi->smi_zone)
24074bff34e3Sthurlow 		return (EPERM);
24084bff34e3Sthurlow 
24094bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
24104bff34e3Sthurlow 		return (EIO);
24114bff34e3Sthurlow 
24124bff34e3Sthurlow 	/*
24134bff34e3Sthurlow 	 * Because we stuff the readdir cookie into the offset field
24144bff34e3Sthurlow 	 * someone may attempt to do an lseek with the cookie which
24154bff34e3Sthurlow 	 * we want to succeed.
24164bff34e3Sthurlow 	 */
24174bff34e3Sthurlow 	if (vp->v_type == VDIR)
24184bff34e3Sthurlow 		return (0);
24194bff34e3Sthurlow 
24204bff34e3Sthurlow 	/* Like NFS3, just check for 63-bit overflow. */
24214bff34e3Sthurlow 	if (*noffp < 0)
24224bff34e3Sthurlow 		return (EINVAL);
24234bff34e3Sthurlow 
24244bff34e3Sthurlow 	return (0);
24254bff34e3Sthurlow }
24264bff34e3Sthurlow 
24274bff34e3Sthurlow 
24284bff34e3Sthurlow /*
24294bff34e3Sthurlow  * XXX
24304bff34e3Sthurlow  * This op may need to support PSARC 2007/440, nbmand changes for CIFS Service.
24314bff34e3Sthurlow  */
24324bff34e3Sthurlow static int
24334bff34e3Sthurlow smbfs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
24344bff34e3Sthurlow 	offset_t offset, struct flk_callback *flk_cbp, cred_t *cr,
24354bff34e3Sthurlow 	caller_context_t *ct)
24364bff34e3Sthurlow {
24374bff34e3Sthurlow 	if (curproc->p_zone != VTOSMI(vp)->smi_zone)
24384bff34e3Sthurlow 		return (EIO);
24394bff34e3Sthurlow 
24404bff34e3Sthurlow 	if (VTOSMI(vp)->smi_flags & SMI_LLOCK)
24414bff34e3Sthurlow 		return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
24424bff34e3Sthurlow 	else
24434bff34e3Sthurlow 		return (ENOSYS);
24444bff34e3Sthurlow }
24454bff34e3Sthurlow 
24464bff34e3Sthurlow /*
24474bff34e3Sthurlow  * Free storage space associated with the specified vnode.  The portion
24484bff34e3Sthurlow  * to be freed is specified by bfp->l_start and bfp->l_len (already
24494bff34e3Sthurlow  * normalized to a "whence" of 0).
24504bff34e3Sthurlow  *
24514bff34e3Sthurlow  * Called by fcntl(fd, F_FREESP, lkp) for libc:ftruncate, etc.
24524bff34e3Sthurlow  */
24534bff34e3Sthurlow /* ARGSUSED */
24544bff34e3Sthurlow static int
24554bff34e3Sthurlow smbfs_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
24564bff34e3Sthurlow 	offset_t offset, cred_t *cr, caller_context_t *ct)
24574bff34e3Sthurlow {
24584bff34e3Sthurlow 	int		error;
24594bff34e3Sthurlow 	smbmntinfo_t	*smi;
24604bff34e3Sthurlow 
24614bff34e3Sthurlow 	smi = VTOSMI(vp);
24624bff34e3Sthurlow 
24634bff34e3Sthurlow 	if (curproc->p_zone != smi->smi_zone)
24644bff34e3Sthurlow 		return (EIO);
24654bff34e3Sthurlow 
24664bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
24674bff34e3Sthurlow 		return (EIO);
24684bff34e3Sthurlow 
24694bff34e3Sthurlow 	ASSERT(vp->v_type == VREG);
24704bff34e3Sthurlow 	if (cmd != F_FREESP)
24714bff34e3Sthurlow 		return (EINVAL);
24724bff34e3Sthurlow 
24734bff34e3Sthurlow 	/*
24744bff34e3Sthurlow 	 * Like NFS3, no 32-bit offset checks here.
24754bff34e3Sthurlow 	 * Our SMB layer takes care to return EFBIG
24764bff34e3Sthurlow 	 * when it has to fallback to a 32-bit call.
24774bff34e3Sthurlow 	 */
24784bff34e3Sthurlow 
24794bff34e3Sthurlow 	error = convoff(vp, bfp, 0, offset);
24804bff34e3Sthurlow 	if (!error) {
24814bff34e3Sthurlow 		ASSERT(bfp->l_start >= 0);
24824bff34e3Sthurlow 		if (bfp->l_len == 0) {
24834bff34e3Sthurlow 			struct vattr va;
24844bff34e3Sthurlow 
24854bff34e3Sthurlow 			/*
24864bff34e3Sthurlow 			 * ftruncate should not change the ctime and
24874bff34e3Sthurlow 			 * mtime if we truncate the file to its
24884bff34e3Sthurlow 			 * previous size.
24894bff34e3Sthurlow 			 */
24904bff34e3Sthurlow 			va.va_mask = AT_SIZE;
24914bff34e3Sthurlow 			error = smbfsgetattr(vp, &va, cr);
24924bff34e3Sthurlow 			if (error || va.va_size == bfp->l_start)
24934bff34e3Sthurlow 				return (error);
24944bff34e3Sthurlow 			va.va_mask = AT_SIZE;
24954bff34e3Sthurlow 			va.va_size = bfp->l_start;
24964bff34e3Sthurlow 			error = smbfssetattr(vp, &va, 0, cr);
24974bff34e3Sthurlow 		} else
24984bff34e3Sthurlow 			error = EINVAL;
24994bff34e3Sthurlow 	}
25004bff34e3Sthurlow 
25014bff34e3Sthurlow 	return (error);
25024bff34e3Sthurlow }
25034bff34e3Sthurlow 
25044bff34e3Sthurlow /* ARGSUSED */
25054bff34e3Sthurlow static int
25064bff34e3Sthurlow smbfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
25074bff34e3Sthurlow 	caller_context_t *ct)
25084bff34e3Sthurlow {
25094bff34e3Sthurlow 	smbmntinfo_t *smi;
25104bff34e3Sthurlow 	struct smb_share *ssp;
25114bff34e3Sthurlow 
25124bff34e3Sthurlow 	smi = VTOSMI(vp);
25134bff34e3Sthurlow 
25144bff34e3Sthurlow 	if (curproc->p_zone != smi->smi_zone)
25154bff34e3Sthurlow 		return (EIO);
25164bff34e3Sthurlow 
25174bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
25184bff34e3Sthurlow 		return (EIO);
25194bff34e3Sthurlow 
25204bff34e3Sthurlow 	switch (cmd) {
25214bff34e3Sthurlow 	case _PC_FILESIZEBITS:
25224bff34e3Sthurlow 		ssp = smi->smi_share;
25234bff34e3Sthurlow 		if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)
25244bff34e3Sthurlow 			*valp = 64;
25254bff34e3Sthurlow 		else
25264bff34e3Sthurlow 			*valp = 32;
25274bff34e3Sthurlow 		break;
25284bff34e3Sthurlow 
25294bff34e3Sthurlow 	case _PC_LINK_MAX:
25304bff34e3Sthurlow 		/* We only ever report one link to an object */
25314bff34e3Sthurlow 		*valp = 1;
25324bff34e3Sthurlow 		break;
25334bff34e3Sthurlow 
2534*7568150aSgwr 	case _PC_ACL_ENABLED:
2535*7568150aSgwr 		/*
2536*7568150aSgwr 		 * Always say "yes" here.  Our _getsecattr
2537*7568150aSgwr 		 * will build a trivial ACL when needed,
2538*7568150aSgwr 		 * i.e. when server does not have ACLs.
2539*7568150aSgwr 		 */
2540*7568150aSgwr 		*valp = _ACL_ACE_ENABLED;
2541*7568150aSgwr 		break;
2542*7568150aSgwr 
25434bff34e3Sthurlow 	case _PC_SYMLINK_MAX:	/* No symlinks until we do Unix extensions */
25444bff34e3Sthurlow 	case _PC_XATTR_EXISTS:	/* No xattrs yet */
25454bff34e3Sthurlow 		*valp = 0;
25464bff34e3Sthurlow 		break;
25474bff34e3Sthurlow 
25484bff34e3Sthurlow 	default:
25494bff34e3Sthurlow 		return (fs_pathconf(vp, cmd, valp, cr, ct));
25504bff34e3Sthurlow 	}
25514bff34e3Sthurlow 	return (0);
25524bff34e3Sthurlow }
25534bff34e3Sthurlow 
2554*7568150aSgwr /* ARGSUSED */
2555*7568150aSgwr static int
2556*7568150aSgwr smbfs_getsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr,
2557*7568150aSgwr 	caller_context_t *ct)
2558*7568150aSgwr {
2559*7568150aSgwr 	vfs_t *vfsp;
2560*7568150aSgwr 	smbmntinfo_t *smi;
2561*7568150aSgwr 	int	error, uid, gid;
2562*7568150aSgwr 	uint_t	mask;
2563*7568150aSgwr 
2564*7568150aSgwr 	vfsp = vp->v_vfsp;
2565*7568150aSgwr 	smi = VFTOSMI(vfsp);
2566*7568150aSgwr 
2567*7568150aSgwr 	if (curproc->p_zone != smi->smi_zone)
2568*7568150aSgwr 		return (EIO);
2569*7568150aSgwr 
2570*7568150aSgwr 	if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
2571*7568150aSgwr 		return (EIO);
2572*7568150aSgwr 
2573*7568150aSgwr 	/*
2574*7568150aSgwr 	 * Our _pathconf indicates _ACL_ACE_ENABLED,
2575*7568150aSgwr 	 * so we should only see VSA_ACE, etc here.
2576*7568150aSgwr 	 * Note: vn_create asks for VSA_DFACLCNT,
2577*7568150aSgwr 	 * and it expects ENOSYS and empty data.
2578*7568150aSgwr 	 */
2579*7568150aSgwr 	mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT |
2580*7568150aSgwr 	    VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES);
2581*7568150aSgwr 	if (mask == 0)
2582*7568150aSgwr 		return (ENOSYS);
2583*7568150aSgwr 
2584*7568150aSgwr 	/* XXX - access check ACE_READ_ACL? */
2585*7568150aSgwr 
2586*7568150aSgwr 	if (smi->smi_fsattr & FILE_PERSISTENT_ACLS) {
2587*7568150aSgwr 		error = smbfs_getacl(vp, vsa, &uid, &gid, flag, cr);
2588*7568150aSgwr 		/* XXX: Save uid/gid somewhere? */
2589*7568150aSgwr 	} else
2590*7568150aSgwr 		error = ENOSYS;
2591*7568150aSgwr 
2592*7568150aSgwr 	if (error == ENOSYS)
2593*7568150aSgwr 		error = fs_fab_acl(vp, vsa, flag, cr, ct);
2594*7568150aSgwr 
2595*7568150aSgwr 	return (error);
2596*7568150aSgwr }
2597*7568150aSgwr 
2598*7568150aSgwr /* ARGSUSED */
2599*7568150aSgwr static int
2600*7568150aSgwr smbfs_setsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr,
2601*7568150aSgwr 	caller_context_t *ct)
2602*7568150aSgwr {
2603*7568150aSgwr 	vfs_t *vfsp;
2604*7568150aSgwr 	smbmntinfo_t *smi;
2605*7568150aSgwr 	int	error;
2606*7568150aSgwr 	uint_t	mask;
2607*7568150aSgwr 
2608*7568150aSgwr 	vfsp = vp->v_vfsp;
2609*7568150aSgwr 	smi = VFTOSMI(vfsp);
2610*7568150aSgwr 
2611*7568150aSgwr 	if (curproc->p_zone != smi->smi_zone)
2612*7568150aSgwr 		return (EIO);
2613*7568150aSgwr 
2614*7568150aSgwr 	if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
2615*7568150aSgwr 		return (EIO);
2616*7568150aSgwr 
2617*7568150aSgwr 	/*
2618*7568150aSgwr 	 * Our _pathconf indicates _ACL_ACE_ENABLED,
2619*7568150aSgwr 	 * so we should only see VSA_ACE, etc here.
2620*7568150aSgwr 	 */
2621*7568150aSgwr 	mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT);
2622*7568150aSgwr 	if (mask == 0)
2623*7568150aSgwr 		return (ENOSYS);
2624*7568150aSgwr 
2625*7568150aSgwr 	/*
2626*7568150aSgwr 	 * If and when smbfs_access is extended, we can
2627*7568150aSgwr 	 * check ACE_WRITE_ACL here instead.  (XXX todo)
2628*7568150aSgwr 	 * For now, in-line parts of smbfs_access,
2629*7568150aSgwr 	 * i.e. only allow _setacl by the owner,
2630*7568150aSgwr 	 * and check for read-only FS.
2631*7568150aSgwr 	 */
2632*7568150aSgwr 	if (vfsp->vfs_flag & VFS_RDONLY)
2633*7568150aSgwr 		return (EROFS);
2634*7568150aSgwr 	if (crgetuid(cr) != smi->smi_args.uid)
2635*7568150aSgwr 		return (EACCES);
2636*7568150aSgwr 
2637*7568150aSgwr 	if (smi->smi_fsattr & FILE_PERSISTENT_ACLS) {
2638*7568150aSgwr 		error = smbfs_setacl(vp, vsa, -1, -1, flag, cr);
2639*7568150aSgwr 	} else
2640*7568150aSgwr 		error = ENOSYS;
2641*7568150aSgwr 
2642*7568150aSgwr 	return (error);
2643*7568150aSgwr }
26444bff34e3Sthurlow 
26454bff34e3Sthurlow 
26464bff34e3Sthurlow /*
26474bff34e3Sthurlow  * XXX
26484bff34e3Sthurlow  * This op should eventually support PSARC 2007/268.
26494bff34e3Sthurlow  */
26504bff34e3Sthurlow static int
26514bff34e3Sthurlow smbfs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
26524bff34e3Sthurlow 	caller_context_t *ct)
26534bff34e3Sthurlow {
26544bff34e3Sthurlow 	if (curproc->p_zone != VTOSMI(vp)->smi_zone)
26554bff34e3Sthurlow 		return (EIO);
26564bff34e3Sthurlow 
26574bff34e3Sthurlow 	if (VTOSMI(vp)->smi_flags & SMI_LLOCK)
26584bff34e3Sthurlow 		return (fs_shrlock(vp, cmd, shr, flag, cr, ct));
26594bff34e3Sthurlow 	else
26604bff34e3Sthurlow 		return (ENOSYS);
26614bff34e3Sthurlow }
2662