14bff34e3Sthurlow /*
24bff34e3Sthurlow  * Copyright (c) 2000-2001 Boris Popov
34bff34e3Sthurlow  * All rights reserved.
44bff34e3Sthurlow  *
54bff34e3Sthurlow  * Redistribution and use in source and binary forms, with or without
64bff34e3Sthurlow  * modification, are permitted provided that the following conditions
74bff34e3Sthurlow  * are met:
84bff34e3Sthurlow  * 1. Redistributions of source code must retain the above copyright
94bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer.
104bff34e3Sthurlow  * 2. Redistributions in binary form must reproduce the above copyright
114bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer in the
124bff34e3Sthurlow  *    documentation and/or other materials provided with the distribution.
134bff34e3Sthurlow  * 3. All advertising materials mentioning features or use of this software
144bff34e3Sthurlow  *    must display the following acknowledgement:
154bff34e3Sthurlow  *    This product includes software developed by Boris Popov.
164bff34e3Sthurlow  * 4. Neither the name of the author nor the names of any co-contributors
174bff34e3Sthurlow  *    may be used to endorse or promote products derived from this software
184bff34e3Sthurlow  *    without specific prior written permission.
194bff34e3Sthurlow  *
204bff34e3Sthurlow  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
214bff34e3Sthurlow  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
224bff34e3Sthurlow  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
234bff34e3Sthurlow  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
244bff34e3Sthurlow  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
254bff34e3Sthurlow  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
264bff34e3Sthurlow  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
274bff34e3Sthurlow  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
284bff34e3Sthurlow  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
294bff34e3Sthurlow  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
304bff34e3Sthurlow  * SUCH DAMAGE.
314bff34e3Sthurlow  *
324bff34e3Sthurlow  * $Id: smbfs_vnops.c,v 1.128.36.1 2005/05/27 02:35:28 lindak Exp $
334bff34e3Sthurlow  */
344bff34e3Sthurlow 
354bff34e3Sthurlow /*
36134a1f4eSCasper H.S. Dik  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
374bff34e3Sthurlow  */
384bff34e3Sthurlow 
394bff34e3Sthurlow #include <sys/systm.h>
404bff34e3Sthurlow #include <sys/cred.h>
414bff34e3Sthurlow #include <sys/vnode.h>
424bff34e3Sthurlow #include <sys/vfs.h>
437568150aSgwr #include <sys/filio.h>
444bff34e3Sthurlow #include <sys/uio.h>
454bff34e3Sthurlow #include <sys/dirent.h>
464bff34e3Sthurlow #include <sys/errno.h>
47613a2f6bSGordon Ross #include <sys/sunddi.h>
484bff34e3Sthurlow #include <sys/sysmacros.h>
494bff34e3Sthurlow #include <sys/kmem.h>
504bff34e3Sthurlow #include <sys/cmn_err.h>
514bff34e3Sthurlow #include <sys/vfs_opreg.h>
524bff34e3Sthurlow #include <sys/policy.h>
534bff34e3Sthurlow 
544bff34e3Sthurlow #include <netsmb/smb_osdep.h>
554bff34e3Sthurlow #include <netsmb/smb.h>
564bff34e3Sthurlow #include <netsmb/smb_conn.h>
574bff34e3Sthurlow #include <netsmb/smb_subr.h>
584bff34e3Sthurlow 
594bff34e3Sthurlow #include <smbfs/smbfs.h>
604bff34e3Sthurlow #include <smbfs/smbfs_node.h>
614bff34e3Sthurlow #include <smbfs/smbfs_subr.h>
624bff34e3Sthurlow 
637568150aSgwr #include <sys/fs/smbfs_ioctl.h>
644bff34e3Sthurlow #include <fs/fs_subr.h>
654bff34e3Sthurlow 
665ecede33SGordon Ross /*
675ecede33SGordon Ross  * We assign directory offsets like the NFS client, where the
685ecede33SGordon Ross  * offset increments by _one_ after each directory entry.
695ecede33SGordon Ross  * Further, the entries "." and ".." are always at offsets
705ecede33SGordon Ross  * zero and one (respectively) and the "real" entries from
715ecede33SGordon Ross  * the server appear at offsets starting with two.  This
725ecede33SGordon Ross  * macro is used to initialize the n_dirofs field after
735ecede33SGordon Ross  * setting n_dirseq with a _findopen call.
745ecede33SGordon Ross  */
755ecede33SGordon Ross #define	FIRST_DIROFS	2
765ecede33SGordon Ross 
774bff34e3Sthurlow /*
784bff34e3Sthurlow  * These characters are illegal in NTFS file names.
794bff34e3Sthurlow  * ref: http://support.microsoft.com/kb/147438
8091d632c8Sgwr  *
8191d632c8Sgwr  * Careful!  The check in the XATTR case skips the
8291d632c8Sgwr  * first character to allow colon in XATTR names.
834bff34e3Sthurlow  */
844bff34e3Sthurlow static const char illegal_chars[] = {
8591d632c8Sgwr 	':',	/* colon - keep this first! */
864bff34e3Sthurlow 	'\\',	/* back slash */
874bff34e3Sthurlow 	'/',	/* slash */
884bff34e3Sthurlow 	'*',	/* asterisk */
894bff34e3Sthurlow 	'?',	/* question mark */
904bff34e3Sthurlow 	'"',	/* double quote */
914bff34e3Sthurlow 	'<',	/* less than sign */
924bff34e3Sthurlow 	'>',	/* greater than sign */
934bff34e3Sthurlow 	'|',	/* vertical bar */
944bff34e3Sthurlow 	0
954bff34e3Sthurlow };
964bff34e3Sthurlow 
974bff34e3Sthurlow /*
984bff34e3Sthurlow  * Turning this on causes nodes to be created in the cache
9902d09e03SGordon Ross  * during directory listings, normally avoiding a second
10002d09e03SGordon Ross  * OtW attribute fetch just after a readdir.
1014bff34e3Sthurlow  */
10202d09e03SGordon Ross int smbfs_fastlookup = 1;
1034bff34e3Sthurlow 
1044bff34e3Sthurlow /* local static function defines */
1054bff34e3Sthurlow 
10602d09e03SGordon Ross static int	smbfslookup_cache(vnode_t *, char *, int, vnode_t **,
10702d09e03SGordon Ross 			cred_t *);
1084bff34e3Sthurlow static int	smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr,
10902d09e03SGordon Ross 			int cache_ok, caller_context_t *);
110*ff1e230cSjilinxpd static int	smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred,
111*ff1e230cSjilinxpd 			int flags);
112*ff1e230cSjilinxpd static int	smbfsrename(vnode_t *odvp, vnode_t *ovp, vnode_t *ndvp,
113*ff1e230cSjilinxpd 			char *nnm, struct smb_cred *scred, int flags);
1144bff34e3Sthurlow static int	smbfssetattr(vnode_t *, struct vattr *, int, cred_t *);
1154bff34e3Sthurlow static int	smbfs_accessx(void *, int, cred_t *);
1164bff34e3Sthurlow static int	smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
1174bff34e3Sthurlow 			caller_context_t *);
11842d15982SGordon Ross static void	smbfs_rele_fid(smbnode_t *, struct smb_cred *);
11928162916SGordon Ross static uint32_t xvattr_to_dosattr(smbnode_t *, struct vattr *);
12042d15982SGordon Ross 
1214bff34e3Sthurlow /*
1224bff34e3Sthurlow  * These are the vnode ops routines which implement the vnode interface to
1234bff34e3Sthurlow  * the networked file system.  These routines just take their parameters,
1244bff34e3Sthurlow  * make them look networkish by putting the right info into interface structs,
1254bff34e3Sthurlow  * and then calling the appropriate remote routine(s) to do the work.
1264bff34e3Sthurlow  *
1274bff34e3Sthurlow  * Note on directory name lookup cacheing:  If we detect a stale fhandle,
1284bff34e3Sthurlow  * we purge the directory cache relative to that vnode.  This way, the
1294bff34e3Sthurlow  * user won't get burned by the cache repeatedly.  See <smbfs/smbnode.h> for
1304bff34e3Sthurlow  * more details on smbnode locking.
1314bff34e3Sthurlow  */
1324bff34e3Sthurlow 
1334bff34e3Sthurlow static int	smbfs_open(vnode_t **, int, cred_t *, caller_context_t *);
1344bff34e3Sthurlow static int	smbfs_close(vnode_t *, int, int, offset_t, cred_t *,
1354bff34e3Sthurlow 			caller_context_t *);
1364bff34e3Sthurlow static int	smbfs_read(vnode_t *, struct uio *, int, cred_t *,
1374bff34e3Sthurlow 			caller_context_t *);
1384bff34e3Sthurlow static int	smbfs_write(vnode_t *, struct uio *, int, cred_t *,
1394bff34e3Sthurlow 			caller_context_t *);
1407568150aSgwr static int	smbfs_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *,
1417568150aSgwr 			caller_context_t *);
1424bff34e3Sthurlow static int	smbfs_getattr(vnode_t *, struct vattr *, int, cred_t *,
1434bff34e3Sthurlow 			caller_context_t *);
1444bff34e3Sthurlow static int	smbfs_setattr(vnode_t *, struct vattr *, int, cred_t *,
1454bff34e3Sthurlow 			caller_context_t *);
1464bff34e3Sthurlow static int	smbfs_access(vnode_t *, int, int, cred_t *, caller_context_t *);
1474bff34e3Sthurlow static int	smbfs_fsync(vnode_t *, int, cred_t *, caller_context_t *);
1484bff34e3Sthurlow static void	smbfs_inactive(vnode_t *, cred_t *, caller_context_t *);
1494bff34e3Sthurlow static int	smbfs_lookup(vnode_t *, char *, vnode_t **, struct pathname *,
1504bff34e3Sthurlow 			int, vnode_t *, cred_t *, caller_context_t *,
1514bff34e3Sthurlow 			int *, pathname_t *);
1524bff34e3Sthurlow static int	smbfs_create(vnode_t *, char *, struct vattr *, enum vcexcl,
1534bff34e3Sthurlow 			int, vnode_t **, cred_t *, int, caller_context_t *,
1544bff34e3Sthurlow 			vsecattr_t *);
1554bff34e3Sthurlow static int	smbfs_remove(vnode_t *, char *, cred_t *, caller_context_t *,
1564bff34e3Sthurlow 			int);
1574bff34e3Sthurlow static int	smbfs_rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
1584bff34e3Sthurlow 			caller_context_t *, int);
1594bff34e3Sthurlow static int	smbfs_mkdir(vnode_t *, char *, struct vattr *, vnode_t **,
1604bff34e3Sthurlow 			cred_t *, caller_context_t *, int, vsecattr_t *);
1614bff34e3Sthurlow static int	smbfs_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
1624bff34e3Sthurlow 			caller_context_t *, int);
1634bff34e3Sthurlow static int	smbfs_readdir(vnode_t *, struct uio *, cred_t *, int *,
1644bff34e3Sthurlow 			caller_context_t *, int);
1654bff34e3Sthurlow static int	smbfs_rwlock(vnode_t *, int, caller_context_t *);
1664bff34e3Sthurlow static void	smbfs_rwunlock(vnode_t *, int, caller_context_t *);
1674bff34e3Sthurlow static int	smbfs_seek(vnode_t *, offset_t, offset_t *, caller_context_t *);
1684bff34e3Sthurlow static int	smbfs_frlock(vnode_t *, int, struct flock64 *, int, offset_t,
1694bff34e3Sthurlow 			struct flk_callback *, cred_t *, caller_context_t *);
1704bff34e3Sthurlow static int	smbfs_space(vnode_t *, int, struct flock64 *, int, offset_t,
1714bff34e3Sthurlow 			cred_t *, caller_context_t *);
1724bff34e3Sthurlow static int	smbfs_pathconf(vnode_t *, int, ulong_t *, cred_t *,
1734bff34e3Sthurlow 			caller_context_t *);
1747568150aSgwr static int	smbfs_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
1757568150aSgwr 			caller_context_t *);
1767568150aSgwr static int	smbfs_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
1777568150aSgwr 			caller_context_t *);
1784bff34e3Sthurlow static int	smbfs_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *,
1794bff34e3Sthurlow 			caller_context_t *);
1804bff34e3Sthurlow 
1814bff34e3Sthurlow /* Dummy function to use until correct function is ported in */
1824bff34e3Sthurlow int noop_vnodeop() {
1834bff34e3Sthurlow 	return (0);
1844bff34e3Sthurlow }
1854bff34e3Sthurlow 
1864bff34e3Sthurlow struct vnodeops *smbfs_vnodeops = NULL;
1874bff34e3Sthurlow 
1884bff34e3Sthurlow /*
1894bff34e3Sthurlow  * Most unimplemented ops will return ENOSYS because of fs_nosys().
1904bff34e3Sthurlow  * The only ops where that won't work are ACCESS (due to open(2)
1917568150aSgwr  * failures) and ... (anything else left?)
1924bff34e3Sthurlow  */
1934bff34e3Sthurlow const fs_operation_def_t smbfs_vnodeops_template[] = {
1947568150aSgwr 	{ VOPNAME_OPEN,		{ .vop_open = smbfs_open } },
1957568150aSgwr 	{ VOPNAME_CLOSE,	{ .vop_close = smbfs_close } },
1967568150aSgwr 	{ VOPNAME_READ,		{ .vop_read = smbfs_read } },
1977568150aSgwr 	{ VOPNAME_WRITE,	{ .vop_write = smbfs_write } },
1987568150aSgwr 	{ VOPNAME_IOCTL,	{ .vop_ioctl = smbfs_ioctl } },
1997568150aSgwr 	{ VOPNAME_GETATTR,	{ .vop_getattr = smbfs_getattr } },
2007568150aSgwr 	{ VOPNAME_SETATTR,	{ .vop_setattr = smbfs_setattr } },
2017568150aSgwr 	{ VOPNAME_ACCESS,	{ .vop_access = smbfs_access } },
2027568150aSgwr 	{ VOPNAME_LOOKUP,	{ .vop_lookup = smbfs_lookup } },
2037568150aSgwr 	{ VOPNAME_CREATE,	{ .vop_create = smbfs_create } },
2047568150aSgwr 	{ VOPNAME_REMOVE,	{ .vop_remove = smbfs_remove } },
2057568150aSgwr 	{ VOPNAME_LINK,		{ .error = fs_nosys } }, /* smbfs_link, */
2067568150aSgwr 	{ VOPNAME_RENAME,	{ .vop_rename = smbfs_rename } },
2077568150aSgwr 	{ VOPNAME_MKDIR,	{ .vop_mkdir = smbfs_mkdir } },
2087568150aSgwr 	{ VOPNAME_RMDIR,	{ .vop_rmdir = smbfs_rmdir } },
2097568150aSgwr 	{ VOPNAME_READDIR,	{ .vop_readdir = smbfs_readdir } },
2107568150aSgwr 	{ VOPNAME_SYMLINK,	{ .error = fs_nosys } }, /* smbfs_symlink, */
2117568150aSgwr 	{ VOPNAME_READLINK,	{ .error = fs_nosys } }, /* smbfs_readlink, */
2127568150aSgwr 	{ VOPNAME_FSYNC,	{ .vop_fsync = smbfs_fsync } },
2137568150aSgwr 	{ VOPNAME_INACTIVE,	{ .vop_inactive = smbfs_inactive } },
2147568150aSgwr 	{ VOPNAME_FID,		{ .error = fs_nosys } }, /* smbfs_fid, */
2157568150aSgwr 	{ VOPNAME_RWLOCK,	{ .vop_rwlock = smbfs_rwlock } },
2167568150aSgwr 	{ VOPNAME_RWUNLOCK,	{ .vop_rwunlock = smbfs_rwunlock } },
2177568150aSgwr 	{ VOPNAME_SEEK,		{ .vop_seek = smbfs_seek } },
2187568150aSgwr 	{ VOPNAME_FRLOCK,	{ .vop_frlock = smbfs_frlock } },
2197568150aSgwr 	{ VOPNAME_SPACE,	{ .vop_space = smbfs_space } },
2207568150aSgwr 	{ VOPNAME_REALVP,	{ .error = fs_nosys } }, /* smbfs_realvp, */
2217568150aSgwr 	{ VOPNAME_GETPAGE,	{ .error = fs_nosys } }, /* smbfs_getpage, */
2227568150aSgwr 	{ VOPNAME_PUTPAGE,	{ .error = fs_nosys } }, /* smbfs_putpage, */
2237568150aSgwr 	{ VOPNAME_MAP,		{ .error = fs_nosys } }, /* smbfs_map, */
2247568150aSgwr 	{ VOPNAME_ADDMAP,	{ .error = fs_nosys } }, /* smbfs_addmap, */
2257568150aSgwr 	{ VOPNAME_DELMAP,	{ .error = fs_nosys } }, /* smbfs_delmap, */
2267568150aSgwr 	{ VOPNAME_DUMP,		{ .error = fs_nosys } }, /* smbfs_dump, */
2277568150aSgwr 	{ VOPNAME_PATHCONF,	{ .vop_pathconf = smbfs_pathconf } },
2287568150aSgwr 	{ VOPNAME_PAGEIO,	{ .error = fs_nosys } }, /* smbfs_pageio, */
2297568150aSgwr 	{ VOPNAME_SETSECATTR,	{ .vop_setsecattr = smbfs_setsecattr } },
2307568150aSgwr 	{ VOPNAME_GETSECATTR,	{ .vop_getsecattr = smbfs_getsecattr } },
2317568150aSgwr 	{ VOPNAME_SHRLOCK,	{ .vop_shrlock = smbfs_shrlock } },
2324bff34e3Sthurlow 	{ NULL, NULL }
2334bff34e3Sthurlow };
2344bff34e3Sthurlow 
2354bff34e3Sthurlow /*
2364bff34e3Sthurlow  * XXX
2374bff34e3Sthurlow  * When new and relevant functionality is enabled, we should be
2384bff34e3Sthurlow  * calling vfs_set_feature() to inform callers that pieces of
2399660e5cbSJanice Chang  * functionality are available, per PSARC 2007/227.
2404bff34e3Sthurlow  */
2414bff34e3Sthurlow /* ARGSUSED */
2424bff34e3Sthurlow static int
2434bff34e3Sthurlow smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
2444bff34e3Sthurlow {
2454bff34e3Sthurlow 	smbnode_t	*np;
2464bff34e3Sthurlow 	vnode_t		*vp;
24702d09e03SGordon Ross 	smbfattr_t	fa;
2484bff34e3Sthurlow 	u_int32_t	rights, rightsrcvd;
2494bff34e3Sthurlow 	u_int16_t	fid, oldfid;
250613a2f6bSGordon Ross 	int		oldgenid;
2514bff34e3Sthurlow 	struct smb_cred scred;
2524bff34e3Sthurlow 	smbmntinfo_t	*smi;
253613a2f6bSGordon Ross 	smb_share_t	*ssp;
2544bff34e3Sthurlow 	cred_t		*oldcr;
2554bff34e3Sthurlow 	int		tmperror;
2564bff34e3Sthurlow 	int		error = 0;
2574bff34e3Sthurlow 
2584bff34e3Sthurlow 	vp = *vpp;
2594bff34e3Sthurlow 	np = VTOSMB(vp);
2604bff34e3Sthurlow 	smi = VTOSMI(vp);
261613a2f6bSGordon Ross 	ssp = smi->smi_share;
2624bff34e3Sthurlow 
263a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
2644bff34e3Sthurlow 		return (EIO);
2654bff34e3Sthurlow 
2664bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2674bff34e3Sthurlow 		return (EIO);
2684bff34e3Sthurlow 
2694bff34e3Sthurlow 	if (vp->v_type != VREG && vp->v_type != VDIR) { /* XXX VLNK? */
2704bff34e3Sthurlow 		SMBVDEBUG("open eacces vtype=%d\n", vp->v_type);
2714bff34e3Sthurlow 		return (EACCES);
2724bff34e3Sthurlow 	}
2734bff34e3Sthurlow 
2744bff34e3Sthurlow 	/*
2754bff34e3Sthurlow 	 * Get exclusive access to n_fid and related stuff.
2764bff34e3Sthurlow 	 * No returns after this until out.
2774bff34e3Sthurlow 	 */
2784bff34e3Sthurlow 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp)))
2794bff34e3Sthurlow 		return (EINTR);
280613a2f6bSGordon Ross 	smb_credinit(&scred, cr);
2814bff34e3Sthurlow 
28291d632c8Sgwr 	/*
28391d632c8Sgwr 	 * Keep track of the vnode type at first open.
28491d632c8Sgwr 	 * It may change later, and we need close to do
28591d632c8Sgwr 	 * cleanup for the type we opened.  Also deny
28691d632c8Sgwr 	 * open of new types until old type is closed.
28791d632c8Sgwr 	 * XXX: Per-open instance nodes whould help.
28891d632c8Sgwr 	 */
28991d632c8Sgwr 	if (np->n_ovtype == VNON) {
29091d632c8Sgwr 		ASSERT(np->n_dirrefs == 0);
29191d632c8Sgwr 		ASSERT(np->n_fidrefs == 0);
29291d632c8Sgwr 	} else if (np->n_ovtype != vp->v_type) {
29391d632c8Sgwr 		SMBVDEBUG("open n_ovtype=%d v_type=%d\n",
29491d632c8Sgwr 		    np->n_ovtype, vp->v_type);
29591d632c8Sgwr 		error = EACCES;
29691d632c8Sgwr 		goto out;
29791d632c8Sgwr 	}
29891d632c8Sgwr 
2994bff34e3Sthurlow 	/*
3005ecede33SGordon Ross 	 * Directory open.  See smbfs_readvdir()
3014bff34e3Sthurlow 	 */
3024bff34e3Sthurlow 	if (vp->v_type == VDIR) {
3035ecede33SGordon Ross 		if (np->n_dirseq == NULL) {
3045ecede33SGordon Ross 			/* first open */
3055ecede33SGordon Ross 			error = smbfs_smb_findopen(np, "*", 1,
3065ecede33SGordon Ross 			    SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR,
3075ecede33SGordon Ross 			    &scred, &np->n_dirseq);
3085ecede33SGordon Ross 			if (error != 0)
3095ecede33SGordon Ross 				goto out;
3105ecede33SGordon Ross 		}
3115ecede33SGordon Ross 		np->n_dirofs = FIRST_DIROFS;
3124bff34e3Sthurlow 		np->n_dirrefs++;
3134bff34e3Sthurlow 		goto have_fid;
3144bff34e3Sthurlow 	}
3154bff34e3Sthurlow 
3164bff34e3Sthurlow 	/*
3174bff34e3Sthurlow 	 * If caller specified O_TRUNC/FTRUNC, then be sure to set
3184bff34e3Sthurlow 	 * FWRITE (to drive successful setattr(size=0) after open)
3194bff34e3Sthurlow 	 */
3204bff34e3Sthurlow 	if (flag & FTRUNC)
3214bff34e3Sthurlow 		flag |= FWRITE;
3224bff34e3Sthurlow 
3234bff34e3Sthurlow 	/*
324613a2f6bSGordon Ross 	 * If we already have it open, and the FID is still valid,
325613a2f6bSGordon Ross 	 * check whether the rights are sufficient for FID reuse.
3264bff34e3Sthurlow 	 */
327613a2f6bSGordon Ross 	if (np->n_fidrefs > 0 &&
328613a2f6bSGordon Ross 	    np->n_vcgenid == ssp->ss_vcgenid) {
3294bff34e3Sthurlow 		int upgrade = 0;
3304bff34e3Sthurlow 
3314bff34e3Sthurlow 		if ((flag & FWRITE) &&
33202d09e03SGordon Ross 		    !(np->n_rights & SA_RIGHT_FILE_WRITE_DATA))
3334bff34e3Sthurlow 			upgrade = 1;
3344bff34e3Sthurlow 		if ((flag & FREAD) &&
33502d09e03SGordon Ross 		    !(np->n_rights & SA_RIGHT_FILE_READ_DATA))
3364bff34e3Sthurlow 			upgrade = 1;
3374bff34e3Sthurlow 		if (!upgrade) {
3384bff34e3Sthurlow 			/*
3394bff34e3Sthurlow 			 *  the existing open is good enough
3404bff34e3Sthurlow 			 */
3414bff34e3Sthurlow 			np->n_fidrefs++;
3424bff34e3Sthurlow 			goto have_fid;
3434bff34e3Sthurlow 		}
3444bff34e3Sthurlow 	}
3454bff34e3Sthurlow 	rights = np->n_fidrefs ? np->n_rights : 0;
3464bff34e3Sthurlow 
3474bff34e3Sthurlow 	/*
3484bff34e3Sthurlow 	 * we always ask for READ_CONTROL so we can always get the
34991d632c8Sgwr 	 * owner/group IDs to satisfy a stat.  Ditto attributes.
3504bff34e3Sthurlow 	 */
35191d632c8Sgwr 	rights |= (STD_RIGHT_READ_CONTROL_ACCESS |
35291d632c8Sgwr 	    SA_RIGHT_FILE_READ_ATTRIBUTES);
3534bff34e3Sthurlow 	if ((flag & FREAD))
3544bff34e3Sthurlow 		rights |= SA_RIGHT_FILE_READ_DATA;
3554bff34e3Sthurlow 	if ((flag & FWRITE))
35602d09e03SGordon Ross 		rights |= SA_RIGHT_FILE_WRITE_DATA |
35702d09e03SGordon Ross 		    SA_RIGHT_FILE_APPEND_DATA |
35802d09e03SGordon Ross 		    SA_RIGHT_FILE_WRITE_ATTRIBUTES;
35902d09e03SGordon Ross 
36002d09e03SGordon Ross 	bzero(&fa, sizeof (fa));
36102d09e03SGordon Ross 	error = smbfs_smb_open(np,
36202d09e03SGordon Ross 	    NULL, 0, 0, /* name nmlen xattr */
36302d09e03SGordon Ross 	    rights, &scred,
36402d09e03SGordon Ross 	    &fid, &rightsrcvd, &fa);
3654bff34e3Sthurlow 	if (error)
3664bff34e3Sthurlow 		goto out;
36702d09e03SGordon Ross 	smbfs_attrcache_fa(vp, &fa);
3684bff34e3Sthurlow 
3694bff34e3Sthurlow 	/*
3704bff34e3Sthurlow 	 * We have a new FID and access rights.
3714bff34e3Sthurlow 	 */
3724bff34e3Sthurlow 	oldfid = np->n_fid;
373613a2f6bSGordon Ross 	oldgenid = np->n_vcgenid;
3744bff34e3Sthurlow 	np->n_fid = fid;
375613a2f6bSGordon Ross 	np->n_vcgenid = ssp->ss_vcgenid;
3764bff34e3Sthurlow 	np->n_rights = rightsrcvd;
3774bff34e3Sthurlow 	np->n_fidrefs++;
378613a2f6bSGordon Ross 	if (np->n_fidrefs > 1 &&
379613a2f6bSGordon Ross 	    oldgenid == ssp->ss_vcgenid) {
3804bff34e3Sthurlow 		/*
3814bff34e3Sthurlow 		 * We already had it open (presumably because
3824bff34e3Sthurlow 		 * it was open with insufficient rights.)
3834bff34e3Sthurlow 		 * Close old wire-open.
3844bff34e3Sthurlow 		 */
385613a2f6bSGordon Ross 		tmperror = smbfs_smb_close(ssp,
38602d09e03SGordon Ross 		    oldfid, NULL, &scred);
3874bff34e3Sthurlow 		if (tmperror)
3884bff34e3Sthurlow 			SMBVDEBUG("error %d closing %s\n",
3894bff34e3Sthurlow 			    tmperror, np->n_rpath);
3904bff34e3Sthurlow 	}
3914bff34e3Sthurlow 
3924bff34e3Sthurlow 	/*
3934bff34e3Sthurlow 	 * This thread did the open.
3944bff34e3Sthurlow 	 * Save our credentials too.
3954bff34e3Sthurlow 	 */
3964bff34e3Sthurlow 	mutex_enter(&np->r_statelock);
3974bff34e3Sthurlow 	oldcr = np->r_cred;
3984bff34e3Sthurlow 	np->r_cred = cr;
3994bff34e3Sthurlow 	crhold(cr);
4004bff34e3Sthurlow 	if (oldcr)
4014bff34e3Sthurlow 		crfree(oldcr);
4024bff34e3Sthurlow 	mutex_exit(&np->r_statelock);
4034bff34e3Sthurlow 
4044bff34e3Sthurlow have_fid:
40591d632c8Sgwr 	/*
40691d632c8Sgwr 	 * Keep track of the vnode type at first open.
40791d632c8Sgwr 	 * (see comments above)
40891d632c8Sgwr 	 */
40991d632c8Sgwr 	if (np->n_ovtype == VNON)
41091d632c8Sgwr 		np->n_ovtype = vp->v_type;
4114bff34e3Sthurlow 
4124bff34e3Sthurlow out:
4134bff34e3Sthurlow 	smb_credrele(&scred);
4144bff34e3Sthurlow 	smbfs_rw_exit(&np->r_lkserlock);
4154bff34e3Sthurlow 	return (error);
4164bff34e3Sthurlow }
4174bff34e3Sthurlow 
4184bff34e3Sthurlow /*ARGSUSED*/
4194bff34e3Sthurlow static int
4204bff34e3Sthurlow smbfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
4214bff34e3Sthurlow 	caller_context_t *ct)
4224bff34e3Sthurlow {
4234bff34e3Sthurlow 	smbnode_t	*np;
424613a2f6bSGordon Ross 	smbmntinfo_t	*smi;
4254bff34e3Sthurlow 	struct smb_cred scred;
4264bff34e3Sthurlow 
4274bff34e3Sthurlow 	np = VTOSMB(vp);
428613a2f6bSGordon Ross 	smi = VTOSMI(vp);
4294bff34e3Sthurlow 
4304bff34e3Sthurlow 	/*
4314bff34e3Sthurlow 	 * Don't "bail out" for VFS_UNMOUNTED here,
4324bff34e3Sthurlow 	 * as we want to do cleanup, etc.
4334bff34e3Sthurlow 	 */
4344bff34e3Sthurlow 
4354bff34e3Sthurlow 	/*
4364bff34e3Sthurlow 	 * zone_enter(2) prevents processes from changing zones with SMBFS files
4374bff34e3Sthurlow 	 * open; if we happen to get here from the wrong zone we can't do
4384bff34e3Sthurlow 	 * anything over the wire.
4394bff34e3Sthurlow 	 */
440a19609f8Sjv 	if (smi->smi_zone_ref.zref_zone != curproc->p_zone) {
4414bff34e3Sthurlow 		/*
4424bff34e3Sthurlow 		 * We could attempt to clean up locks, except we're sure
4434bff34e3Sthurlow 		 * that the current process didn't acquire any locks on
4444bff34e3Sthurlow 		 * the file: any attempt to lock a file belong to another zone
4454bff34e3Sthurlow 		 * will fail, and one can't lock an SMBFS file and then change
4464bff34e3Sthurlow 		 * zones, as that fails too.
4474bff34e3Sthurlow 		 *
4484bff34e3Sthurlow 		 * Returning an error here is the sane thing to do.  A
4494bff34e3Sthurlow 		 * subsequent call to VN_RELE() which translates to a
4504bff34e3Sthurlow 		 * smbfs_inactive() will clean up state: if the zone of the
4514bff34e3Sthurlow 		 * vnode's origin is still alive and kicking, an async worker
4524bff34e3Sthurlow 		 * thread will handle the request (from the correct zone), and
4534bff34e3Sthurlow 		 * everything (minus the final smbfs_getattr_otw() call) should
4544bff34e3Sthurlow 		 * be OK. If the zone is going away smbfs_async_inactive() will
4554bff34e3Sthurlow 		 * throw away cached pages inline.
4564bff34e3Sthurlow 		 */
4574bff34e3Sthurlow 		return (EIO);
4584bff34e3Sthurlow 	}
4594bff34e3Sthurlow 
4604bff34e3Sthurlow 	/*
4614bff34e3Sthurlow 	 * If we are using local locking for this filesystem, then
4624bff34e3Sthurlow 	 * release all of the SYSV style record locks.  Otherwise,
4634bff34e3Sthurlow 	 * we are doing network locking and we need to release all
4644bff34e3Sthurlow 	 * of the network locks.  All of the locks held by this
4654bff34e3Sthurlow 	 * process on this file are released no matter what the
4664bff34e3Sthurlow 	 * incoming reference count is.
4674bff34e3Sthurlow 	 */
46842d15982SGordon Ross 	if (smi->smi_flags & SMI_LLOCK) {
469613a2f6bSGordon Ross 		pid_t pid = ddi_get_pid();
470613a2f6bSGordon Ross 		cleanlocks(vp, pid, 0);
471613a2f6bSGordon Ross 		cleanshares(vp, pid);
4724bff34e3Sthurlow 	}
4734bff34e3Sthurlow 
4744bff34e3Sthurlow 	/*
47502d09e03SGordon Ross 	 * This (passed in) count is the ref. count from the
47602d09e03SGordon Ross 	 * user's file_t before the closef call (fio.c).
47702d09e03SGordon Ross 	 * We only care when the reference goes away.
4784bff34e3Sthurlow 	 */
47902d09e03SGordon Ross 	if (count > 1)
48002d09e03SGordon Ross 		return (0);
4814bff34e3Sthurlow 
4824bff34e3Sthurlow 	/*
48342d15982SGordon Ross 	 * Decrement the reference count for the FID
48442d15982SGordon Ross 	 * and possibly do the OtW close.
48542d15982SGordon Ross 	 *
4864bff34e3Sthurlow 	 * Exclusive lock for modifying n_fid stuff.
4874bff34e3Sthurlow 	 * Don't want this one ever interruptible.
4884bff34e3Sthurlow 	 */
4894bff34e3Sthurlow 	(void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
490613a2f6bSGordon Ross 	smb_credinit(&scred, cr);
4914bff34e3Sthurlow 
49242d15982SGordon Ross 	smbfs_rele_fid(np, &scred);
49342d15982SGordon Ross 
49442d15982SGordon Ross 	smb_credrele(&scred);
49542d15982SGordon Ross 	smbfs_rw_exit(&np->r_lkserlock);
49642d15982SGordon Ross 
49742d15982SGordon Ross 	return (0);
49842d15982SGordon Ross }
49942d15982SGordon Ross 
50042d15982SGordon Ross /*
50142d15982SGordon Ross  * Helper for smbfs_close.  Decrement the reference count
50242d15982SGordon Ross  * for an SMB-level file or directory ID, and when the last
50342d15982SGordon Ross  * reference for the fid goes away, do the OtW close.
50442d15982SGordon Ross  * Also called in smbfs_inactive (defensive cleanup).
50542d15982SGordon Ross  */
50642d15982SGordon Ross static void
50742d15982SGordon Ross smbfs_rele_fid(smbnode_t *np, struct smb_cred *scred)
50842d15982SGordon Ross {
50942d15982SGordon Ross 	smb_share_t	*ssp;
51042d15982SGordon Ross 	cred_t		*oldcr;
51142d15982SGordon Ross 	struct smbfs_fctx *fctx;
51242d15982SGordon Ross 	int		error;
51342d15982SGordon Ross 	uint16_t ofid;
51442d15982SGordon Ross 
51542d15982SGordon Ross 	ssp = np->n_mount->smi_share;
5164bff34e3Sthurlow 	error = 0;
51791d632c8Sgwr 
51842d15982SGordon Ross 	/* Make sure we serialize for n_dirseq use. */
51942d15982SGordon Ross 	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_WRITER));
52042d15982SGordon Ross 
52191d632c8Sgwr 	/*
52291d632c8Sgwr 	 * Note that vp->v_type may change if a remote node
52391d632c8Sgwr 	 * is deleted and recreated as a different type, and
52491d632c8Sgwr 	 * our getattr may change v_type accordingly.
52591d632c8Sgwr 	 * Now use n_ovtype to keep track of the v_type
52691d632c8Sgwr 	 * we had during open (see comments above).
52791d632c8Sgwr 	 */
52842d15982SGordon Ross 	switch (np->n_ovtype) {
52942d15982SGordon Ross 	case VDIR:
5304bff34e3Sthurlow 		ASSERT(np->n_dirrefs > 0);
5314bff34e3Sthurlow 		if (--np->n_dirrefs)
53242d15982SGordon Ross 			return;
5334bff34e3Sthurlow 		if ((fctx = np->n_dirseq) != NULL) {
5344bff34e3Sthurlow 			np->n_dirseq = NULL;
5355ecede33SGordon Ross 			np->n_dirofs = 0;
53642d15982SGordon Ross 			error = smbfs_smb_findclose(fctx, scred);
5374bff34e3Sthurlow 		}
53842d15982SGordon Ross 		break;
53942d15982SGordon Ross 
54042d15982SGordon Ross 	case VREG:
5414bff34e3Sthurlow 		ASSERT(np->n_fidrefs > 0);
5424bff34e3Sthurlow 		if (--np->n_fidrefs)
54342d15982SGordon Ross 			return;
5444bff34e3Sthurlow 		if ((ofid = np->n_fid) != SMB_FID_UNUSED) {
5454bff34e3Sthurlow 			np->n_fid = SMB_FID_UNUSED;
546613a2f6bSGordon Ross 			/* After reconnect, n_fid is invalid */
547613a2f6bSGordon Ross 			if (np->n_vcgenid == ssp->ss_vcgenid) {
548613a2f6bSGordon Ross 				error = smbfs_smb_close(
54942d15982SGordon Ross 				    ssp, ofid, NULL, scred);
550613a2f6bSGordon Ross 			}
5514bff34e3Sthurlow 		}
55242d15982SGordon Ross 		break;
55342d15982SGordon Ross 
55442d15982SGordon Ross 	default:
55542d15982SGordon Ross 		SMBVDEBUG("bad n_ovtype %d\n", np->n_ovtype);
55642d15982SGordon Ross 		break;
5574bff34e3Sthurlow 	}
5584bff34e3Sthurlow 	if (error) {
55902d09e03SGordon Ross 		SMBVDEBUG("error %d closing %s\n",
5604bff34e3Sthurlow 		    error, np->n_rpath);
5614bff34e3Sthurlow 	}
5624bff34e3Sthurlow 
56391d632c8Sgwr 	/* Allow next open to use any v_type. */
56491d632c8Sgwr 	np->n_ovtype = VNON;
56591d632c8Sgwr 
56602d09e03SGordon Ross 	/*
56702d09e03SGordon Ross 	 * Other "last close" stuff.
56802d09e03SGordon Ross 	 */
56902d09e03SGordon Ross 	mutex_enter(&np->r_statelock);
5704bff34e3Sthurlow 	if (np->n_flag & NATTRCHANGED)
57102d09e03SGordon Ross 		smbfs_attrcache_rm_locked(np);
57202d09e03SGordon Ross 	oldcr = np->r_cred;
57302d09e03SGordon Ross 	np->r_cred = NULL;
57402d09e03SGordon Ross 	mutex_exit(&np->r_statelock);
57502d09e03SGordon Ross 	if (oldcr != NULL)
57602d09e03SGordon Ross 		crfree(oldcr);
5774bff34e3Sthurlow }
5784bff34e3Sthurlow 
5794bff34e3Sthurlow /* ARGSUSED */
5804bff34e3Sthurlow static int
5814bff34e3Sthurlow smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
5824bff34e3Sthurlow 	caller_context_t *ct)
5834bff34e3Sthurlow {
5849c9af259SGordon Ross 	struct smb_cred scred;
5859c9af259SGordon Ross 	struct vattr	va;
586613a2f6bSGordon Ross 	smbnode_t	*np;
587613a2f6bSGordon Ross 	smbmntinfo_t	*smi;
588613a2f6bSGordon Ross 	smb_share_t	*ssp;
5899c9af259SGordon Ross 	offset_t	endoff;
5909c9af259SGordon Ross 	ssize_t		past_eof;
5919c9af259SGordon Ross 	int		error;
5924bff34e3Sthurlow 
5934bff34e3Sthurlow 	np = VTOSMB(vp);
5944bff34e3Sthurlow 	smi = VTOSMI(vp);
595613a2f6bSGordon Ross 	ssp = smi->smi_share;
5964bff34e3Sthurlow 
597a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
5984bff34e3Sthurlow 		return (EIO);
5994bff34e3Sthurlow 
6004bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
6014bff34e3Sthurlow 		return (EIO);
6024bff34e3Sthurlow 
6034bff34e3Sthurlow 	ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER));
6044bff34e3Sthurlow 
6054bff34e3Sthurlow 	if (vp->v_type != VREG)
6064bff34e3Sthurlow 		return (EISDIR);
6074bff34e3Sthurlow 
6084bff34e3Sthurlow 	if (uiop->uio_resid == 0)
6094bff34e3Sthurlow 		return (0);
6104bff34e3Sthurlow 
6114bff34e3Sthurlow 	/*
6124bff34e3Sthurlow 	 * Like NFS3, just check for 63-bit overflow.
6134bff34e3Sthurlow 	 * Our SMB layer takes care to return EFBIG
6144bff34e3Sthurlow 	 * when it has to fallback to a 32-bit call.
6154bff34e3Sthurlow 	 */
616613a2f6bSGordon Ross 	endoff = uiop->uio_loffset + uiop->uio_resid;
617613a2f6bSGordon Ross 	if (uiop->uio_loffset < 0 || endoff < 0)
6184bff34e3Sthurlow 		return (EINVAL);
6194bff34e3Sthurlow 
6204bff34e3Sthurlow 	/* get vnode attributes from server */
6214bff34e3Sthurlow 	va.va_mask = AT_SIZE | AT_MTIME;
6224bff34e3Sthurlow 	if (error = smbfsgetattr(vp, &va, cr))
6239c9af259SGordon Ross 		return (error);
6244bff34e3Sthurlow 
6259c9af259SGordon Ross 	/* Update mtime with mtime from server here? */
6269c9af259SGordon Ross 
6279c9af259SGordon Ross 	/* if offset is beyond EOF, read nothing */
6289c9af259SGordon Ross 	if (uiop->uio_loffset >= va.va_size)
6299c9af259SGordon Ross 		return (0);
6304bff34e3Sthurlow 
6314bff34e3Sthurlow 	/*
6329c9af259SGordon Ross 	 * Limit the read to the remaining file size.
6339c9af259SGordon Ross 	 * Do this by temporarily reducing uio_resid
6349c9af259SGordon Ross 	 * by the amount the lies beyoned the EOF.
6354bff34e3Sthurlow 	 */
6369c9af259SGordon Ross 	if (endoff > va.va_size) {
6379c9af259SGordon Ross 		past_eof = (ssize_t)(endoff - va.va_size);
6389c9af259SGordon Ross 		uiop->uio_resid -= past_eof;
6399c9af259SGordon Ross 	} else
6409c9af259SGordon Ross 		past_eof = 0;
6419c9af259SGordon Ross 
6429c9af259SGordon Ross 	/* Shared lock for n_fid use in smb_rwuio */
6439c9af259SGordon Ross 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
6449c9af259SGordon Ross 		return (EINTR);
645613a2f6bSGordon Ross 	smb_credinit(&scred, cr);
6464bff34e3Sthurlow 
647613a2f6bSGordon Ross 	/* After reconnect, n_fid is invalid */
648613a2f6bSGordon Ross 	if (np->n_vcgenid != ssp->ss_vcgenid)
649613a2f6bSGordon Ross 		error = ESTALE;
650613a2f6bSGordon Ross 	else
651613a2f6bSGordon Ross 		error = smb_rwuio(ssp, np->n_fid, UIO_READ,
652613a2f6bSGordon Ross 		    uiop, &scred, smb_timo_read);
6539c9af259SGordon Ross 
6549c9af259SGordon Ross 	smb_credrele(&scred);
6554bff34e3Sthurlow 	smbfs_rw_exit(&np->r_lkserlock);
6564bff34e3Sthurlow 
6579c9af259SGordon Ross 	/* undo adjustment of resid */
6589c9af259SGordon Ross 	uiop->uio_resid += past_eof;
6599c9af259SGordon Ross 
6609c9af259SGordon Ross 	return (error);
6614bff34e3Sthurlow }
6624bff34e3Sthurlow 
6634bff34e3Sthurlow 
6644bff34e3Sthurlow /* ARGSUSED */
6654bff34e3Sthurlow static int
6664bff34e3Sthurlow smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
6674bff34e3Sthurlow 	caller_context_t *ct)
6684bff34e3Sthurlow {
6699c9af259SGordon Ross 	struct smb_cred scred;
6709c9af259SGordon Ross 	struct vattr	va;
671613a2f6bSGordon Ross 	smbnode_t	*np;
672613a2f6bSGordon Ross 	smbmntinfo_t	*smi;
673613a2f6bSGordon Ross 	smb_share_t	*ssp;
6749c9af259SGordon Ross 	offset_t	endoff, limit;
6759c9af259SGordon Ross 	ssize_t		past_limit;
6769c9af259SGordon Ross 	int		error, timo;
6774bff34e3Sthurlow 
6784bff34e3Sthurlow 	np = VTOSMB(vp);
6794bff34e3Sthurlow 	smi = VTOSMI(vp);
680613a2f6bSGordon Ross 	ssp = smi->smi_share;
6814bff34e3Sthurlow 
682a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
6834bff34e3Sthurlow 		return (EIO);
6844bff34e3Sthurlow 
6854bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
6864bff34e3Sthurlow 		return (EIO);
6874bff34e3Sthurlow 
6884bff34e3Sthurlow 	ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_WRITER));
6894bff34e3Sthurlow 
6904bff34e3Sthurlow 	if (vp->v_type != VREG)
6914bff34e3Sthurlow 		return (EISDIR);
6924bff34e3Sthurlow 
6934bff34e3Sthurlow 	if (uiop->uio_resid == 0)
6944bff34e3Sthurlow 		return (0);
6954bff34e3Sthurlow 
6969c9af259SGordon Ross 	/*
6979c9af259SGordon Ross 	 * Handle ioflag bits: (FAPPEND|FSYNC|FDSYNC)
6989c9af259SGordon Ross 	 */
6999c9af259SGordon Ross 	if (ioflag & (FAPPEND | FSYNC)) {
7009c9af259SGordon Ross 		if (np->n_flag & NMODIFIED) {
70102d09e03SGordon Ross 			smbfs_attrcache_remove(np);
7029c9af259SGordon Ross 			/* XXX: smbfs_vinvalbuf? */
7039c9af259SGordon Ross 		}
7049c9af259SGordon Ross 	}
7059c9af259SGordon Ross 	if (ioflag & FAPPEND) {
7069c9af259SGordon Ross 		/*
7079c9af259SGordon Ross 		 * File size can be changed by another client
7089c9af259SGordon Ross 		 */
7099c9af259SGordon Ross 		va.va_mask = AT_SIZE;
7109c9af259SGordon Ross 		if (error = smbfsgetattr(vp, &va, cr))
7119c9af259SGordon Ross 			return (error);
7129c9af259SGordon Ross 		uiop->uio_loffset = va.va_size;
7139c9af259SGordon Ross 	}
7144bff34e3Sthurlow 
7159c9af259SGordon Ross 	/*
7169c9af259SGordon Ross 	 * Like NFS3, just check for 63-bit overflow.
7179c9af259SGordon Ross 	 */
7189c9af259SGordon Ross 	endoff = uiop->uio_loffset + uiop->uio_resid;
7199c9af259SGordon Ross 	if (uiop->uio_loffset < 0 || endoff < 0)
7209c9af259SGordon Ross 		return (EINVAL);
7214bff34e3Sthurlow 
7224bff34e3Sthurlow 	/*
7239c9af259SGordon Ross 	 * Check to make sure that the process will not exceed
7249c9af259SGordon Ross 	 * its limit on file size.  It is okay to write up to
7259c9af259SGordon Ross 	 * the limit, but not beyond.  Thus, the write which
7269c9af259SGordon Ross 	 * reaches the limit will be short and the next write
7279c9af259SGordon Ross 	 * will return an error.
7289c9af259SGordon Ross 	 *
7299c9af259SGordon Ross 	 * So if we're starting at or beyond the limit, EFBIG.
7309c9af259SGordon Ross 	 * Otherwise, temporarily reduce resid to the amount
7319c9af259SGordon Ross 	 * the falls after the limit.
7324bff34e3Sthurlow 	 */
7339c9af259SGordon Ross 	limit = uiop->uio_llimit;
7349c9af259SGordon Ross 	if (limit == RLIM64_INFINITY || limit > MAXOFFSET_T)
7359c9af259SGordon Ross 		limit = MAXOFFSET_T;
7369c9af259SGordon Ross 	if (uiop->uio_loffset >= limit)
7379c9af259SGordon Ross 		return (EFBIG);
7389c9af259SGordon Ross 	if (endoff > limit) {
7399c9af259SGordon Ross 		past_limit = (ssize_t)(endoff - limit);
7409c9af259SGordon Ross 		uiop->uio_resid -= past_limit;
7419c9af259SGordon Ross 	} else
7429c9af259SGordon Ross 		past_limit = 0;
7439c9af259SGordon Ross 
7449c9af259SGordon Ross 	/* Timeout: longer for append. */
7459c9af259SGordon Ross 	timo = smb_timo_write;
74602d09e03SGordon Ross 	if (endoff > np->r_size)
7479c9af259SGordon Ross 		timo = smb_timo_append;
7489c9af259SGordon Ross 
7499c9af259SGordon Ross 	/* Shared lock for n_fid use in smb_rwuio */
7509c9af259SGordon Ross 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
7519c9af259SGordon Ross 		return (EINTR);
752613a2f6bSGordon Ross 	smb_credinit(&scred, cr);
7534bff34e3Sthurlow 
754613a2f6bSGordon Ross 	/* After reconnect, n_fid is invalid */
755613a2f6bSGordon Ross 	if (np->n_vcgenid != ssp->ss_vcgenid)
756613a2f6bSGordon Ross 		error = ESTALE;
757613a2f6bSGordon Ross 	else
758613a2f6bSGordon Ross 		error = smb_rwuio(ssp, np->n_fid, UIO_WRITE,
759613a2f6bSGordon Ross 		    uiop, &scred, timo);
7609c9af259SGordon Ross 
7619c9af259SGordon Ross 	if (error == 0) {
7629c9af259SGordon Ross 		mutex_enter(&np->r_statelock);
7639c9af259SGordon Ross 		np->n_flag |= (NFLUSHWIRE | NATTRCHANGED);
76402d09e03SGordon Ross 		if (uiop->uio_loffset > (offset_t)np->r_size)
76502d09e03SGordon Ross 			np->r_size = (len_t)uiop->uio_loffset;
7669c9af259SGordon Ross 		mutex_exit(&np->r_statelock);
7679c9af259SGordon Ross 		if (ioflag & (FSYNC|FDSYNC)) {
7689c9af259SGordon Ross 			/* Don't error the I/O if this fails. */
7699c9af259SGordon Ross 			(void) smbfs_smb_flush(np, &scred);
7709c9af259SGordon Ross 		}
7719c9af259SGordon Ross 	}
7729c9af259SGordon Ross 
7739c9af259SGordon Ross 	smb_credrele(&scred);
7744bff34e3Sthurlow 	smbfs_rw_exit(&np->r_lkserlock);
7754bff34e3Sthurlow 
7769c9af259SGordon Ross 	/* undo adjustment of resid */
7779c9af259SGordon Ross 	uiop->uio_resid += past_limit;
7789c9af259SGordon Ross 
7799c9af259SGordon Ross 	return (error);
7804bff34e3Sthurlow }
7814bff34e3Sthurlow 
7824bff34e3Sthurlow 
7837568150aSgwr /* ARGSUSED */
7847568150aSgwr static int
7857568150aSgwr smbfs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag,
7867568150aSgwr 	cred_t *cr, int *rvalp,	caller_context_t *ct)
7877568150aSgwr {
7887568150aSgwr 	int		error;
7897568150aSgwr 	smbmntinfo_t 	*smi;
7907568150aSgwr 
7917568150aSgwr 	smi = VTOSMI(vp);
7927568150aSgwr 
793a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
7947568150aSgwr 		return (EIO);
7957568150aSgwr 
7967568150aSgwr 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
7977568150aSgwr 		return (EIO);
7987568150aSgwr 
7997568150aSgwr 	switch (cmd) {
8007568150aSgwr 		/* First three from ZFS. XXX - need these? */
8017568150aSgwr 
8027568150aSgwr 	case _FIOFFS:
8037568150aSgwr 		error = smbfs_fsync(vp, 0, cr, ct);
8047568150aSgwr 		break;
8057568150aSgwr 
8067568150aSgwr 		/*
8077568150aSgwr 		 * The following two ioctls are used by bfu.
8087568150aSgwr 		 * Silently ignore to avoid bfu errors.
8097568150aSgwr 		 */
8107568150aSgwr 	case _FIOGDIO:
8117568150aSgwr 	case _FIOSDIO:
8127568150aSgwr 		error = 0;
8137568150aSgwr 		break;
8147568150aSgwr 
8157568150aSgwr #ifdef NOT_YET	/* XXX - from the NFS code. */
8167568150aSgwr 	case _FIODIRECTIO:
8177568150aSgwr 		error = smbfs_directio(vp, (int)arg, cr);
8187568150aSgwr #endif
8197568150aSgwr 
8207568150aSgwr 		/*
8217568150aSgwr 		 * Allow get/set with "raw" security descriptor (SD) data.
8227568150aSgwr 		 * Useful for testing, diagnosing idmap problems, etc.
8237568150aSgwr 		 */
8247568150aSgwr 	case SMBFSIO_GETSD:
825bd7c6f51SGordon Ross 		error = smbfs_acl_iocget(vp, arg, flag, cr);
8267568150aSgwr 		break;
8277568150aSgwr 
8287568150aSgwr 	case SMBFSIO_SETSD:
829bd7c6f51SGordon Ross 		error = smbfs_acl_iocset(vp, arg, flag, cr);
8307568150aSgwr 		break;
8317568150aSgwr 
8327568150aSgwr 	default:
8337568150aSgwr 		error = ENOTTY;
8347568150aSgwr 		break;
8357568150aSgwr 	}
8367568150aSgwr 
8377568150aSgwr 	return (error);
8387568150aSgwr }
8397568150aSgwr 
8407568150aSgwr 
8414bff34e3Sthurlow /*
8424bff34e3Sthurlow  * Return either cached or remote attributes. If get remote attr
8434bff34e3Sthurlow  * use them to check and invalidate caches, then cache the new attributes.
8444bff34e3Sthurlow  */
8454bff34e3Sthurlow /* ARGSUSED */
8464bff34e3Sthurlow static int
8474bff34e3Sthurlow smbfs_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
8484bff34e3Sthurlow 	caller_context_t *ct)
8494bff34e3Sthurlow {
8504bff34e3Sthurlow 	smbnode_t *np;
8514bff34e3Sthurlow 	smbmntinfo_t *smi;
8524bff34e3Sthurlow 
8534bff34e3Sthurlow 	smi = VTOSMI(vp);
8544bff34e3Sthurlow 
855a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
8564bff34e3Sthurlow 		return (EIO);
8574bff34e3Sthurlow 
8584bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
8594bff34e3Sthurlow 		return (EIO);
8604bff34e3Sthurlow 
8614bff34e3Sthurlow 	/*
8624bff34e3Sthurlow 	 * If it has been specified that the return value will
8634bff34e3Sthurlow 	 * just be used as a hint, and we are only being asked
8644bff34e3Sthurlow 	 * for size, fsid or rdevid, then return the client's
8654bff34e3Sthurlow 	 * notion of these values without checking to make sure
8664bff34e3Sthurlow 	 * that the attribute cache is up to date.
8674bff34e3Sthurlow 	 * The whole point is to avoid an over the wire GETATTR
8684bff34e3Sthurlow 	 * call.
8694bff34e3Sthurlow 	 */
8704bff34e3Sthurlow 	np = VTOSMB(vp);
8714bff34e3Sthurlow 	if (flags & ATTR_HINT) {
8724bff34e3Sthurlow 		if (vap->va_mask ==
8734bff34e3Sthurlow 		    (vap->va_mask & (AT_SIZE | AT_FSID | AT_RDEV))) {
8744bff34e3Sthurlow 			mutex_enter(&np->r_statelock);
8754bff34e3Sthurlow 			if (vap->va_mask | AT_SIZE)
8764bff34e3Sthurlow 				vap->va_size = np->r_size;
8774bff34e3Sthurlow 			if (vap->va_mask | AT_FSID)
87802d09e03SGordon Ross 				vap->va_fsid = vp->v_vfsp->vfs_dev;
8794bff34e3Sthurlow 			if (vap->va_mask | AT_RDEV)
88002d09e03SGordon Ross 				vap->va_rdev = vp->v_rdev;
8814bff34e3Sthurlow 			mutex_exit(&np->r_statelock);
8824bff34e3Sthurlow 			return (0);
8834bff34e3Sthurlow 		}
8844bff34e3Sthurlow 	}
8854bff34e3Sthurlow 
8864bff34e3Sthurlow 	return (smbfsgetattr(vp, vap, cr));
8874bff34e3Sthurlow }
8884bff34e3Sthurlow 
88902d09e03SGordon Ross /* smbfsgetattr() in smbfs_client.c */
8904bff34e3Sthurlow 
8914bff34e3Sthurlow /*ARGSUSED4*/
8924bff34e3Sthurlow static int
8934bff34e3Sthurlow smbfs_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
8944bff34e3Sthurlow 		caller_context_t *ct)
8954bff34e3Sthurlow {
89602d09e03SGordon Ross 	vfs_t		*vfsp;
89702d09e03SGordon Ross 	smbmntinfo_t	*smi;
8984bff34e3Sthurlow 	int		error;
8994bff34e3Sthurlow 	uint_t		mask;
9004bff34e3Sthurlow 	struct vattr	oldva;
9014bff34e3Sthurlow 
90202d09e03SGordon Ross 	vfsp = vp->v_vfsp;
90302d09e03SGordon Ross 	smi = VFTOSMI(vfsp);
9044bff34e3Sthurlow 
905a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
9064bff34e3Sthurlow 		return (EIO);
9074bff34e3Sthurlow 
90802d09e03SGordon Ross 	if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
9094bff34e3Sthurlow 		return (EIO);
9104bff34e3Sthurlow 
9114bff34e3Sthurlow 	mask = vap->va_mask;
9124bff34e3Sthurlow 	if (mask & AT_NOSET)
9134bff34e3Sthurlow 		return (EINVAL);
9144bff34e3Sthurlow 
91502d09e03SGordon Ross 	if (vfsp->vfs_flag & VFS_RDONLY)
91602d09e03SGordon Ross 		return (EROFS);
91702d09e03SGordon Ross 
918bd7c6f51SGordon Ross 	/*
919bd7c6f51SGordon Ross 	 * This is a _local_ access check so that only the owner of
920bd7c6f51SGordon Ross 	 * this mount can set attributes.  With ACLs enabled, the
921bd7c6f51SGordon Ross 	 * file owner can be different from the mount owner, and we
922bd7c6f51SGordon Ross 	 * need to check the _mount_ owner here.  See _access_rwx
923bd7c6f51SGordon Ross 	 */
92402d09e03SGordon Ross 	bzero(&oldva, sizeof (oldva));
925bd7c6f51SGordon Ross 	oldva.va_mask = AT_TYPE | AT_MODE;
9264bff34e3Sthurlow 	error = smbfsgetattr(vp, &oldva, cr);
9274bff34e3Sthurlow 	if (error)
9284bff34e3Sthurlow 		return (error);
929bd7c6f51SGordon Ross 	oldva.va_mask |= AT_UID | AT_GID;
930bd7c6f51SGordon Ross 	oldva.va_uid = smi->smi_uid;
931bd7c6f51SGordon Ross 	oldva.va_gid = smi->smi_gid;
9324bff34e3Sthurlow 
9334bff34e3Sthurlow 	error = secpolicy_vnode_setattr(cr, vp, vap, &oldva, flags,
9344bff34e3Sthurlow 	    smbfs_accessx, vp);
9354bff34e3Sthurlow 	if (error)
9364bff34e3Sthurlow 		return (error);
9374bff34e3Sthurlow 
938bd7c6f51SGordon Ross 	if (mask & (AT_UID | AT_GID)) {
939bd7c6f51SGordon Ross 		if (smi->smi_flags & SMI_ACL)
940bd7c6f51SGordon Ross 			error = smbfs_acl_setids(vp, vap, cr);
941bd7c6f51SGordon Ross 		else
942bd7c6f51SGordon Ross 			error = ENOSYS;
943bd7c6f51SGordon Ross 		if (error != 0) {
944bd7c6f51SGordon Ross 			SMBVDEBUG("error %d seting UID/GID on %s",
945bd7c6f51SGordon Ross 			    error, VTOSMB(vp)->n_rpath);
946bd7c6f51SGordon Ross 			/*
947bd7c6f51SGordon Ross 			 * It might be more correct to return the
948bd7c6f51SGordon Ross 			 * error here, but that causes complaints
949bd7c6f51SGordon Ross 			 * when root extracts a cpio archive, etc.
950bd7c6f51SGordon Ross 			 * So ignore this error, and go ahead with
951bd7c6f51SGordon Ross 			 * the rest of the setattr work.
952bd7c6f51SGordon Ross 			 */
953bd7c6f51SGordon Ross 		}
954bd7c6f51SGordon Ross 	}
955bd7c6f51SGordon Ross 
9564bff34e3Sthurlow 	return (smbfssetattr(vp, vap, flags, cr));
9574bff34e3Sthurlow }
9584bff34e3Sthurlow 
9594bff34e3Sthurlow /*
9604bff34e3Sthurlow  * Mostly from Darwin smbfs_setattr()
9614bff34e3Sthurlow  * but then modified a lot.
9624bff34e3Sthurlow  */
9634bff34e3Sthurlow /* ARGSUSED */
9644bff34e3Sthurlow static int
9654bff34e3Sthurlow smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
9664bff34e3Sthurlow {
9674bff34e3Sthurlow 	int		error = 0;
9684bff34e3Sthurlow 	smbnode_t	*np = VTOSMB(vp);
9694bff34e3Sthurlow 	uint_t		mask = vap->va_mask;
9704bff34e3Sthurlow 	struct timespec	*mtime, *atime;
9714bff34e3Sthurlow 	struct smb_cred	scred;
9724bff34e3Sthurlow 	int		cerror, modified = 0;
9734bff34e3Sthurlow 	unsigned short	fid;
9744bff34e3Sthurlow 	int have_fid = 0;
9754bff34e3Sthurlow 	uint32_t rights = 0;
97628162916SGordon Ross 	uint32_t dosattr = 0;
9774bff34e3Sthurlow 
978a19609f8Sjv 	ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone_ref.zref_zone);
9794bff34e3Sthurlow 
98091d632c8Sgwr 	/*
98191d632c8Sgwr 	 * There are no settable attributes on the XATTR dir,
98291d632c8Sgwr 	 * so just silently ignore these.  On XATTR files,
98391d632c8Sgwr 	 * you can set the size but nothing else.
98491d632c8Sgwr 	 */
98591d632c8Sgwr 	if (vp->v_flag & V_XATTRDIR)
98691d632c8Sgwr 		return (0);
98791d632c8Sgwr 	if (np->n_flag & N_XATTR) {
98891d632c8Sgwr 		if (mask & AT_TIMES)
98991d632c8Sgwr 			SMBVDEBUG("ignore set time on xattr\n");
99091d632c8Sgwr 		mask &= AT_SIZE;
99191d632c8Sgwr 	}
99291d632c8Sgwr 
9934bff34e3Sthurlow 	/*
9944bff34e3Sthurlow 	 * If our caller is trying to set multiple attributes, they
9954bff34e3Sthurlow 	 * can make no assumption about what order they are done in.
9964bff34e3Sthurlow 	 * Here we try to do them in order of decreasing likelihood
9974bff34e3Sthurlow 	 * of failure, just to minimize the chance we'll wind up
9984bff34e3Sthurlow 	 * with a partially complete request.
9994bff34e3Sthurlow 	 */
10004bff34e3Sthurlow 
10014bff34e3Sthurlow 	/* Shared lock for (possible) n_fid use. */
10024bff34e3Sthurlow 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
10034bff34e3Sthurlow 		return (EINTR);
1004613a2f6bSGordon Ross 	smb_credinit(&scred, cr);
10054bff34e3Sthurlow 
100628162916SGordon Ross 	/*
100728162916SGordon Ross 	 * If the caller has provided extensible attributes,
100828162916SGordon Ross 	 * map those into DOS attributes supported by SMB.
100928162916SGordon Ross 	 * Note: zero means "no change".
101028162916SGordon Ross 	 */
101128162916SGordon Ross 	if (mask & AT_XVATTR)
101228162916SGordon Ross 		dosattr = xvattr_to_dosattr(np, vap);
101328162916SGordon Ross 
10144bff34e3Sthurlow 	/*
10154bff34e3Sthurlow 	 * Will we need an open handle for this setattr?
10164bff34e3Sthurlow 	 * If so, what rights will we need?
10174bff34e3Sthurlow 	 */
101828162916SGordon Ross 	if (dosattr || (mask & (AT_ATIME | AT_MTIME))) {
10194bff34e3Sthurlow 		rights |=
102002d09e03SGordon Ross 		    SA_RIGHT_FILE_WRITE_ATTRIBUTES;
10214bff34e3Sthurlow 	}
10224bff34e3Sthurlow 	if (mask & AT_SIZE) {
10234bff34e3Sthurlow 		rights |=
10244bff34e3Sthurlow 		    SA_RIGHT_FILE_WRITE_DATA |
10254bff34e3Sthurlow 		    SA_RIGHT_FILE_APPEND_DATA;
102602d09e03SGordon Ross 	}
102702d09e03SGordon Ross 
102802d09e03SGordon Ross 	/*
102902d09e03SGordon Ross 	 * Only SIZE really requires a handle, but it's
103002d09e03SGordon Ross 	 * simpler and more reliable to set via a handle.
103102d09e03SGordon Ross 	 * Some servers like NT4 won't set times by path.
103202d09e03SGordon Ross 	 * Also, we're usually setting everything anyway.
103302d09e03SGordon Ross 	 */
103428162916SGordon Ross 	if (rights != 0) {
10354bff34e3Sthurlow 		error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
10364bff34e3Sthurlow 		if (error) {
10374bff34e3Sthurlow 			SMBVDEBUG("error %d opening %s\n",
10384bff34e3Sthurlow 			    error, np->n_rpath);
10394bff34e3Sthurlow 			goto out;
10404bff34e3Sthurlow 		}
10414bff34e3Sthurlow 		have_fid = 1;
10424bff34e3Sthurlow 	}
10434bff34e3Sthurlow 
10444bff34e3Sthurlow 	/*
10454bff34e3Sthurlow 	 * If the server supports the UNIX extensions, right here is where
10464bff34e3Sthurlow 	 * we'd support changes to uid, gid, mode, and possibly va_flags.
10474bff34e3Sthurlow 	 * For now we claim to have made any such changes.
10484bff34e3Sthurlow 	 */
10494bff34e3Sthurlow 
10504bff34e3Sthurlow 	if (mask & AT_SIZE) {
10514bff34e3Sthurlow 		/*
10524bff34e3Sthurlow 		 * If the new file size is less than what the client sees as
10534bff34e3Sthurlow 		 * the file size, then just change the size and invalidate
10544bff34e3Sthurlow 		 * the pages.
10554bff34e3Sthurlow 		 * I am commenting this code at present because the function
10564bff34e3Sthurlow 		 * smbfs_putapage() is not yet implemented.
10574bff34e3Sthurlow 		 */
10584bff34e3Sthurlow 
10594bff34e3Sthurlow 		/*
10604bff34e3Sthurlow 		 * Set the file size to vap->va_size.
10614bff34e3Sthurlow 		 */
10624bff34e3Sthurlow 		ASSERT(have_fid);
10634bff34e3Sthurlow 		error = smbfs_smb_setfsize(np, fid, vap->va_size, &scred);
10644bff34e3Sthurlow 		if (error) {
10654bff34e3Sthurlow 			SMBVDEBUG("setsize error %d file %s\n",
10664bff34e3Sthurlow 			    error, np->n_rpath);
10674bff34e3Sthurlow 		} else {
10684bff34e3Sthurlow 			/*
10694bff34e3Sthurlow 			 * Darwin had code here to zero-extend.
10704bff34e3Sthurlow 			 * Tests indicate the server will zero-fill,
10714bff34e3Sthurlow 			 * so looks like we don't need to do this.
10724bff34e3Sthurlow 			 * Good thing, as this could take forever.
1073613a2f6bSGordon Ross 			 *
1074613a2f6bSGordon Ross 			 * XXX: Reportedly, writing one byte of zero
1075613a2f6bSGordon Ross 			 * at the end offset avoids problems here.
10764bff34e3Sthurlow 			 */
10774bff34e3Sthurlow 			mutex_enter(&np->r_statelock);
10784bff34e3Sthurlow 			np->r_size = vap->va_size;
10794bff34e3Sthurlow 			mutex_exit(&np->r_statelock);
10804bff34e3Sthurlow 			modified = 1;
10814bff34e3Sthurlow 		}
10824bff34e3Sthurlow 	}
10834bff34e3Sthurlow 
10844bff34e3Sthurlow 	/*
10854bff34e3Sthurlow 	 * XXX: When Solaris has create_time, set that too.
10864bff34e3Sthurlow 	 * Note: create_time is different from ctime.
10874bff34e3Sthurlow 	 */
10884bff34e3Sthurlow 	mtime = ((mask & AT_MTIME) ? &vap->va_mtime : 0);
10894bff34e3Sthurlow 	atime = ((mask & AT_ATIME) ? &vap->va_atime : 0);
10904bff34e3Sthurlow 
109128162916SGordon Ross 	if (dosattr || mtime || atime) {
10924bff34e3Sthurlow 		/*
109302d09e03SGordon Ross 		 * Always use the handle-based set attr call now.
10944bff34e3Sthurlow 		 */
109502d09e03SGordon Ross 		ASSERT(have_fid);
109602d09e03SGordon Ross 		error = smbfs_smb_setfattr(np, fid,
109728162916SGordon Ross 		    dosattr, mtime, atime, &scred);
10984bff34e3Sthurlow 		if (error) {
10994bff34e3Sthurlow 			SMBVDEBUG("set times error %d file %s\n",
11004bff34e3Sthurlow 			    error, np->n_rpath);
11014bff34e3Sthurlow 		} else {
11024bff34e3Sthurlow 			modified = 1;
11034bff34e3Sthurlow 		}
11044bff34e3Sthurlow 	}
11054bff34e3Sthurlow 
11064bff34e3Sthurlow out:
11074bff34e3Sthurlow 	if (modified) {
11084bff34e3Sthurlow 		/*
110902d09e03SGordon Ross 		 * Invalidate attribute cache in case the server
111002d09e03SGordon Ross 		 * doesn't set exactly the attributes we asked.
11114bff34e3Sthurlow 		 */
111202d09e03SGordon Ross 		smbfs_attrcache_remove(np);
11134bff34e3Sthurlow 	}
11144bff34e3Sthurlow 
11154bff34e3Sthurlow 	if (have_fid) {
11164bff34e3Sthurlow 		cerror = smbfs_smb_tmpclose(np, fid, &scred);
11174bff34e3Sthurlow 		if (cerror)
111802d09e03SGordon Ross 			SMBVDEBUG("error %d closing %s\n",
11194bff34e3Sthurlow 			    cerror, np->n_rpath);
11204bff34e3Sthurlow 	}
11214bff34e3Sthurlow 
11224bff34e3Sthurlow 	smb_credrele(&scred);
11234bff34e3Sthurlow 	smbfs_rw_exit(&np->r_lkserlock);
11244bff34e3Sthurlow 
11254bff34e3Sthurlow 	return (error);
11264bff34e3Sthurlow }
11274bff34e3Sthurlow 
112828162916SGordon Ross /*
112928162916SGordon Ross  * Helper function for extensible system attributes (PSARC 2007/315)
113028162916SGordon Ross  * Compute the DOS attribute word to pass to _setfattr (see above).
113128162916SGordon Ross  * This returns zero IFF no change is being made to attributes.
113228162916SGordon Ross  * Otherwise return the new attributes or SMB_EFA_NORMAL.
113328162916SGordon Ross  */
113428162916SGordon Ross static uint32_t
113528162916SGordon Ross xvattr_to_dosattr(smbnode_t *np, struct vattr *vap)
113628162916SGordon Ross {
113728162916SGordon Ross 	xvattr_t *xvap = (xvattr_t *)vap;
113828162916SGordon Ross 	xoptattr_t *xoap = NULL;
113928162916SGordon Ross 	uint32_t attr = np->r_attr.fa_attr;
114028162916SGordon Ross 	boolean_t anyset = B_FALSE;
114128162916SGordon Ross 
114228162916SGordon Ross 	if ((xoap = xva_getxoptattr(xvap)) == NULL)
114328162916SGordon Ross 		return (0);
114428162916SGordon Ross 
114528162916SGordon Ross 	if (XVA_ISSET_REQ(xvap, XAT_ARCHIVE)) {
114628162916SGordon Ross 		if (xoap->xoa_archive)
114728162916SGordon Ross 			attr |= SMB_FA_ARCHIVE;
114828162916SGordon Ross 		else
114928162916SGordon Ross 			attr &= ~SMB_FA_ARCHIVE;
115028162916SGordon Ross 		XVA_SET_RTN(xvap, XAT_ARCHIVE);
115128162916SGordon Ross 		anyset = B_TRUE;
115228162916SGordon Ross 	}
115328162916SGordon Ross 	if (XVA_ISSET_REQ(xvap, XAT_SYSTEM)) {
115428162916SGordon Ross 		if (xoap->xoa_system)
115528162916SGordon Ross 			attr |= SMB_FA_SYSTEM;
115628162916SGordon Ross 		else
115728162916SGordon Ross 			attr &= ~SMB_FA_SYSTEM;
115828162916SGordon Ross 		XVA_SET_RTN(xvap, XAT_SYSTEM);
115928162916SGordon Ross 		anyset = B_TRUE;
116028162916SGordon Ross 	}
116128162916SGordon Ross 	if (XVA_ISSET_REQ(xvap, XAT_READONLY)) {
116228162916SGordon Ross 		if (xoap->xoa_readonly)
116328162916SGordon Ross 			attr |= SMB_FA_RDONLY;
116428162916SGordon Ross 		else
116528162916SGordon Ross 			attr &= ~SMB_FA_RDONLY;
116628162916SGordon Ross 		XVA_SET_RTN(xvap, XAT_READONLY);
116728162916SGordon Ross 		anyset = B_TRUE;
116828162916SGordon Ross 	}
116928162916SGordon Ross 	if (XVA_ISSET_REQ(xvap, XAT_HIDDEN)) {
117028162916SGordon Ross 		if (xoap->xoa_hidden)
117128162916SGordon Ross 			attr |= SMB_FA_HIDDEN;
117228162916SGordon Ross 		else
117328162916SGordon Ross 			attr &= ~SMB_FA_HIDDEN;
117428162916SGordon Ross 		XVA_SET_RTN(xvap, XAT_HIDDEN);
117528162916SGordon Ross 		anyset = B_TRUE;
117628162916SGordon Ross 	}
117728162916SGordon Ross 
117828162916SGordon Ross 	if (anyset == B_FALSE)
117928162916SGordon Ross 		return (0);	/* no change */
118028162916SGordon Ross 	if (attr == 0)
118128162916SGordon Ross 		attr = SMB_EFA_NORMAL;
118228162916SGordon Ross 
118328162916SGordon Ross 	return (attr);
118428162916SGordon Ross }
118528162916SGordon Ross 
11864bff34e3Sthurlow /*
11874bff34e3Sthurlow  * smbfs_access_rwx()
11884bff34e3Sthurlow  * Common function for smbfs_access, etc.
11894bff34e3Sthurlow  *
11904bff34e3Sthurlow  * The security model implemented by the FS is unusual
1191bd7c6f51SGordon Ross  * due to the current "single user mounts" restriction:
11924bff34e3Sthurlow  * All access under a given mount point uses the CIFS
11934bff34e3Sthurlow  * credentials established by the owner of the mount.
11944bff34e3Sthurlow  *
11954bff34e3Sthurlow  * Most access checking is handled by the CIFS server,
11964bff34e3Sthurlow  * but we need sufficient Unix access checks here to
11974bff34e3Sthurlow  * prevent other local Unix users from having access
11984bff34e3Sthurlow  * to objects under this mount that the uid/gid/mode
11994bff34e3Sthurlow  * settings in the mount would not allow.
12004bff34e3Sthurlow  *
12014bff34e3Sthurlow  * With this model, there is a case where we need the
12024bff34e3Sthurlow  * ability to do an access check before we have the
12034bff34e3Sthurlow  * vnode for an object.  This function takes advantage
12044bff34e3Sthurlow  * of the fact that the uid/gid/mode is per mount, and
12054bff34e3Sthurlow  * avoids the need for a vnode.
12064bff34e3Sthurlow  *
12074bff34e3Sthurlow  * We still (sort of) need a vnode when we call
12084bff34e3Sthurlow  * secpolicy_vnode_access, but that only uses
12094bff34e3Sthurlow  * the vtype field, so we can use a pair of fake
12104bff34e3Sthurlow  * vnodes that have only v_type filled in.
12114bff34e3Sthurlow  *
12124bff34e3Sthurlow  * XXX: Later, add a new secpolicy_vtype_access()
12134bff34e3Sthurlow  * that takes the vtype instead of a vnode, and
12144bff34e3Sthurlow  * get rid of the tmpl_vxxx fake vnodes below.
12154bff34e3Sthurlow  */
12164bff34e3Sthurlow static int
12174bff34e3Sthurlow smbfs_access_rwx(vfs_t *vfsp, int vtype, int mode, cred_t *cr)
12184bff34e3Sthurlow {
12194bff34e3Sthurlow 	/* See the secpolicy call below. */
12204bff34e3Sthurlow 	static const vnode_t tmpl_vdir = { .v_type = VDIR };
12214bff34e3Sthurlow 	static const vnode_t tmpl_vreg = { .v_type = VREG };
12224bff34e3Sthurlow 	vattr_t		va;
12234bff34e3Sthurlow 	vnode_t		*tvp;
12244bff34e3Sthurlow 	struct smbmntinfo *smi = VFTOSMI(vfsp);
12254bff34e3Sthurlow 	int shift = 0;
12264bff34e3Sthurlow 
12274bff34e3Sthurlow 	/*
12284bff34e3Sthurlow 	 * Build our (fabricated) vnode attributes.
12294bff34e3Sthurlow 	 * XXX: Could make these templates in the
12304bff34e3Sthurlow 	 * per-mount struct and use them here.
12314bff34e3Sthurlow 	 */
12324bff34e3Sthurlow 	bzero(&va, sizeof (va));
12334bff34e3Sthurlow 	va.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
12344bff34e3Sthurlow 	va.va_type = vtype;
12354bff34e3Sthurlow 	va.va_mode = (vtype == VDIR) ?
123602d09e03SGordon Ross 	    smi->smi_dmode : smi->smi_fmode;
123702d09e03SGordon Ross 	va.va_uid = smi->smi_uid;
123802d09e03SGordon Ross 	va.va_gid = smi->smi_gid;
12394bff34e3Sthurlow 
12404bff34e3Sthurlow 	/*
12414bff34e3Sthurlow 	 * Disallow write attempts on read-only file systems,
12424bff34e3Sthurlow 	 * unless the file is a device or fifo node.  Note:
12434bff34e3Sthurlow 	 * Inline vn_is_readonly and IS_DEVVP here because
12444bff34e3Sthurlow 	 * we may not have a vnode ptr.  Original expr. was:
12454bff34e3Sthurlow 	 * (mode & VWRITE) && vn_is_readonly(vp) && !IS_DEVVP(vp))
12464bff34e3Sthurlow 	 */
12474bff34e3Sthurlow 	if ((mode & VWRITE) &&
12484bff34e3Sthurlow 	    (vfsp->vfs_flag & VFS_RDONLY) &&
12494bff34e3Sthurlow 	    !(vtype == VCHR || vtype == VBLK || vtype == VFIFO))
12504bff34e3Sthurlow 		return (EROFS);
12514bff34e3Sthurlow 
12524bff34e3Sthurlow 	/*
12534bff34e3Sthurlow 	 * Disallow attempts to access mandatory lock files.
12544bff34e3Sthurlow 	 * Similarly, expand MANDLOCK here.
12554bff34e3Sthurlow 	 * XXX: not sure we need this.
12564bff34e3Sthurlow 	 */
12574bff34e3Sthurlow 	if ((mode & (VWRITE | VREAD | VEXEC)) &&
12584bff34e3Sthurlow 	    va.va_type == VREG && MANDMODE(va.va_mode))
12594bff34e3Sthurlow 		return (EACCES);
12604bff34e3Sthurlow 
12614bff34e3Sthurlow 	/*
12624bff34e3Sthurlow 	 * Access check is based on only
12634bff34e3Sthurlow 	 * one of owner, group, public.
12644bff34e3Sthurlow 	 * If not owner, then check group.
12654bff34e3Sthurlow 	 * If not a member of the group,
12664bff34e3Sthurlow 	 * then check public access.
12674bff34e3Sthurlow 	 */
12684bff34e3Sthurlow 	if (crgetuid(cr) != va.va_uid) {
12694bff34e3Sthurlow 		shift += 3;
12704bff34e3Sthurlow 		if (!groupmember(va.va_gid, cr))
12714bff34e3Sthurlow 			shift += 3;
12724bff34e3Sthurlow 	}
12734bff34e3Sthurlow 
12744bff34e3Sthurlow 	/*
12754bff34e3Sthurlow 	 * We need a vnode for secpolicy_vnode_access,
12764bff34e3Sthurlow 	 * but the only thing it looks at is v_type,
12774bff34e3Sthurlow 	 * so pass one of the templates above.
12784bff34e3Sthurlow 	 */
12794bff34e3Sthurlow 	tvp = (va.va_type == VDIR) ?
12804bff34e3Sthurlow 	    (vnode_t *)&tmpl_vdir :
12814bff34e3Sthurlow 	    (vnode_t *)&tmpl_vreg;
1282134a1f4eSCasper H.S. Dik 
1283134a1f4eSCasper H.S. Dik 	return (secpolicy_vnode_access2(cr, tvp, va.va_uid,
1284134a1f4eSCasper H.S. Dik 	    va.va_mode << shift, mode));
12854bff34e3Sthurlow }
12864bff34e3Sthurlow 
12874bff34e3Sthurlow /*
12884bff34e3Sthurlow  * See smbfs_setattr
12894bff34e3Sthurlow  */
12904bff34e3Sthurlow static int
12914bff34e3Sthurlow smbfs_accessx(void *arg, int mode, cred_t *cr)
12924bff34e3Sthurlow {
12934bff34e3Sthurlow 	vnode_t *vp = arg;
12944bff34e3Sthurlow 	/*
12954bff34e3Sthurlow 	 * Note: The caller has checked the current zone,
12964bff34e3Sthurlow 	 * the SMI_DEAD and VFS_UNMOUNTED flags, etc.
12974bff34e3Sthurlow 	 */
12984bff34e3Sthurlow 	return (smbfs_access_rwx(vp->v_vfsp, vp->v_type, mode, cr));
12994bff34e3Sthurlow }
13004bff34e3Sthurlow 
13014bff34e3Sthurlow /*
13024bff34e3Sthurlow  * XXX
13034bff34e3Sthurlow  * This op should support PSARC 2007/403, Modified Access Checks for CIFS
13044bff34e3Sthurlow  */
13054bff34e3Sthurlow /* ARGSUSED */
13064bff34e3Sthurlow static int
13074bff34e3Sthurlow smbfs_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
13084bff34e3Sthurlow {
13094bff34e3Sthurlow 	vfs_t		*vfsp;
13104bff34e3Sthurlow 	smbmntinfo_t	*smi;
13114bff34e3Sthurlow 
13124bff34e3Sthurlow 	vfsp = vp->v_vfsp;
13134bff34e3Sthurlow 	smi = VFTOSMI(vfsp);
13144bff34e3Sthurlow 
1315a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
13164bff34e3Sthurlow 		return (EIO);
13174bff34e3Sthurlow 
13184bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
13194bff34e3Sthurlow 		return (EIO);
13204bff34e3Sthurlow 
13214bff34e3Sthurlow 	return (smbfs_access_rwx(vfsp, vp->v_type, mode, cr));
13224bff34e3Sthurlow }
13234bff34e3Sthurlow 
13244bff34e3Sthurlow 
13254bff34e3Sthurlow /*
13264bff34e3Sthurlow  * Flush local dirty pages to stable storage on the server.
13274bff34e3Sthurlow  *
13284bff34e3Sthurlow  * If FNODSYNC is specified, then there is nothing to do because
13294bff34e3Sthurlow  * metadata changes are not cached on the client before being
13304bff34e3Sthurlow  * sent to the server.
13314bff34e3Sthurlow  */
13324bff34e3Sthurlow /* ARGSUSED */
13334bff34e3Sthurlow static int
13344bff34e3Sthurlow smbfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
13354bff34e3Sthurlow {
13364bff34e3Sthurlow 	int		error = 0;
13374bff34e3Sthurlow 	smbmntinfo_t	*smi;
13382f5e3e91SGordon Ross 	smbnode_t 	*np;
13392f5e3e91SGordon Ross 	struct smb_cred scred;
13404bff34e3Sthurlow 
13412f5e3e91SGordon Ross 	np = VTOSMB(vp);
13424bff34e3Sthurlow 	smi = VTOSMI(vp);
13434bff34e3Sthurlow 
1344a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
13454bff34e3Sthurlow 		return (EIO);
13464bff34e3Sthurlow 
13474bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
13484bff34e3Sthurlow 		return (EIO);
13494bff34e3Sthurlow 
13504bff34e3Sthurlow 	if ((syncflag & FNODSYNC) || IS_SWAPVP(vp))
13514bff34e3Sthurlow 		return (0);
13524bff34e3Sthurlow 
13532f5e3e91SGordon Ross 	if ((syncflag & (FSYNC|FDSYNC)) == 0)
13542f5e3e91SGordon Ross 		return (0);
13552f5e3e91SGordon Ross 
13562f5e3e91SGordon Ross 	/* Shared lock for n_fid use in _flush */
13572f5e3e91SGordon Ross 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
13582f5e3e91SGordon Ross 		return (EINTR);
1359613a2f6bSGordon Ross 	smb_credinit(&scred, cr);
13602f5e3e91SGordon Ross 
13612f5e3e91SGordon Ross 	error = smbfs_smb_flush(np, &scred);
13622f5e3e91SGordon Ross 
13632f5e3e91SGordon Ross 	smb_credrele(&scred);
13642f5e3e91SGordon Ross 	smbfs_rw_exit(&np->r_lkserlock);
13652f5e3e91SGordon Ross 
13664bff34e3Sthurlow 	return (error);
13674bff34e3Sthurlow }
13684bff34e3Sthurlow 
13694bff34e3Sthurlow /*
13704bff34e3Sthurlow  * Last reference to vnode went away.
13714bff34e3Sthurlow  */
13724bff34e3Sthurlow /* ARGSUSED */
13734bff34e3Sthurlow static void
13744bff34e3Sthurlow smbfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
13754bff34e3Sthurlow {
13764bff34e3Sthurlow 	smbnode_t	*np;
137742d15982SGordon Ross 	struct smb_cred scred;
13784bff34e3Sthurlow 
13794bff34e3Sthurlow 	/*
13804bff34e3Sthurlow 	 * Don't "bail out" for VFS_UNMOUNTED here,
13814bff34e3Sthurlow 	 * as we want to do cleanup, etc.
13824bff34e3Sthurlow 	 * See also pcfs_inactive
13834bff34e3Sthurlow 	 */
13844bff34e3Sthurlow 
13854bff34e3Sthurlow 	np = VTOSMB(vp);
13864bff34e3Sthurlow 
13874bff34e3Sthurlow 	/*
13884bff34e3Sthurlow 	 * If this is coming from the wrong zone, we let someone in the right
13894bff34e3Sthurlow 	 * zone take care of it asynchronously.  We can get here due to
13904bff34e3Sthurlow 	 * VN_RELE() being called from pageout() or fsflush().  This call may
13914bff34e3Sthurlow 	 * potentially turn into an expensive no-op if, for instance, v_count
13924bff34e3Sthurlow 	 * gets incremented in the meantime, but it's still correct.
13934bff34e3Sthurlow 	 */
13944bff34e3Sthurlow 
13954bff34e3Sthurlow 	/*
139642d15982SGordon Ross 	 * Defend against the possibility that higher-level callers
139742d15982SGordon Ross 	 * might not correctly balance open and close calls.  If we
139842d15982SGordon Ross 	 * get here with open references remaining, it means there
139942d15982SGordon Ross 	 * was a missing VOP_CLOSE somewhere.  If that happens, do
140042d15982SGordon Ross 	 * the close here so we don't "leak" FIDs on the server.
14014bff34e3Sthurlow 	 *
140242d15982SGordon Ross 	 * Exclusive lock for modifying n_fid stuff.
140342d15982SGordon Ross 	 * Don't want this one ever interruptible.
14044bff34e3Sthurlow 	 */
140542d15982SGordon Ross 	(void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
140642d15982SGordon Ross 	smb_credinit(&scred, cr);
140742d15982SGordon Ross 
140842d15982SGordon Ross 	switch (np->n_ovtype) {
140942d15982SGordon Ross 	case VNON:
141042d15982SGordon Ross 		/* not open (OK) */
141142d15982SGordon Ross 		break;
141242d15982SGordon Ross 
141342d15982SGordon Ross 	case VDIR:
141442d15982SGordon Ross 		if (np->n_dirrefs == 0)
141542d15982SGordon Ross 			break;
141642d15982SGordon Ross 		SMBVDEBUG("open dir: refs %d path %s\n",
141742d15982SGordon Ross 		    np->n_dirrefs, np->n_rpath);
141842d15982SGordon Ross 		/* Force last close. */
141942d15982SGordon Ross 		np->n_dirrefs = 1;
142042d15982SGordon Ross 		smbfs_rele_fid(np, &scred);
142142d15982SGordon Ross 		break;
142242d15982SGordon Ross 
142342d15982SGordon Ross 	case VREG:
142442d15982SGordon Ross 		if (np->n_fidrefs == 0)
142542d15982SGordon Ross 			break;
142642d15982SGordon Ross 		SMBVDEBUG("open file: refs %d id 0x%x path %s\n",
14274bff34e3Sthurlow 		    np->n_fidrefs, np->n_fid, np->n_rpath);
142842d15982SGordon Ross 		/* Force last close. */
142942d15982SGordon Ross 		np->n_fidrefs = 1;
143042d15982SGordon Ross 		smbfs_rele_fid(np, &scred);
143142d15982SGordon Ross 		break;
143242d15982SGordon Ross 
143342d15982SGordon Ross 	default:
143442d15982SGordon Ross 		SMBVDEBUG("bad n_ovtype %d\n", np->n_ovtype);
143542d15982SGordon Ross 		np->n_ovtype = VNON;
143642d15982SGordon Ross 		break;
14374bff34e3Sthurlow 	}
143842d15982SGordon Ross 
143942d15982SGordon Ross 	smb_credrele(&scred);
144042d15982SGordon Ross 	smbfs_rw_exit(&np->r_lkserlock);
14414bff34e3Sthurlow 
1442*ff1e230cSjilinxpd 	/*
1443*ff1e230cSjilinxpd 	 * XATTR directories (and the files under them) have
1444*ff1e230cSjilinxpd 	 * little value for reclaim, so just remove them from
1445*ff1e230cSjilinxpd 	 * the "hash" (AVL) as soon as they go inactive.
1446*ff1e230cSjilinxpd 	 * Note that the node may already have been removed
1447*ff1e230cSjilinxpd 	 * from the hash by smbfsremove.
1448*ff1e230cSjilinxpd 	 */
1449*ff1e230cSjilinxpd 	if ((np->n_flag & N_XATTR) != 0 &&
1450*ff1e230cSjilinxpd 	    (np->r_flags & RHASHED) != 0)
1451*ff1e230cSjilinxpd 		smbfs_rmhash(np);
1452*ff1e230cSjilinxpd 
145302d09e03SGordon Ross 	smbfs_addfree(np);
14544bff34e3Sthurlow }
14554bff34e3Sthurlow 
14564bff34e3Sthurlow /*
14574bff34e3Sthurlow  * Remote file system operations having to do with directory manipulation.
14584bff34e3Sthurlow  */
14594bff34e3Sthurlow /* ARGSUSED */
14604bff34e3Sthurlow static int
14614bff34e3Sthurlow smbfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
14624bff34e3Sthurlow 	int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
14634bff34e3Sthurlow 	int *direntflags, pathname_t *realpnp)
14644bff34e3Sthurlow {
146591d632c8Sgwr 	vfs_t		*vfs;
14664bff34e3Sthurlow 	smbmntinfo_t	*smi;
146791d632c8Sgwr 	smbnode_t	*dnp;
146891d632c8Sgwr 	int		error;
14694bff34e3Sthurlow 
147091d632c8Sgwr 	vfs = dvp->v_vfsp;
147191d632c8Sgwr 	smi = VFTOSMI(vfs);
14724bff34e3Sthurlow 
1473a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
14744bff34e3Sthurlow 		return (EPERM);
14754bff34e3Sthurlow 
147691d632c8Sgwr 	if (smi->smi_flags & SMI_DEAD || vfs->vfs_flag & VFS_UNMOUNTED)
14774bff34e3Sthurlow 		return (EIO);
14784bff34e3Sthurlow 
14794bff34e3Sthurlow 	dnp = VTOSMB(dvp);
148091d632c8Sgwr 
148191d632c8Sgwr 	/*
148291d632c8Sgwr 	 * Are we looking up extended attributes?  If so, "dvp" is
148391d632c8Sgwr 	 * the file or directory for which we want attributes, and
148491d632c8Sgwr 	 * we need a lookup of the (faked up) attribute directory
148591d632c8Sgwr 	 * before we lookup the rest of the path.
148691d632c8Sgwr 	 */
148791d632c8Sgwr 	if (flags & LOOKUP_XATTR) {
148891d632c8Sgwr 		/*
148991d632c8Sgwr 		 * Require the xattr mount option.
149091d632c8Sgwr 		 */
149191d632c8Sgwr 		if ((vfs->vfs_flag & VFS_XATTR) == 0)
149291d632c8Sgwr 			return (EINVAL);
149391d632c8Sgwr 
149491d632c8Sgwr 		error = smbfs_get_xattrdir(dvp, vpp, cr, flags);
149591d632c8Sgwr 		return (error);
149691d632c8Sgwr 	}
149791d632c8Sgwr 
149802d09e03SGordon Ross 	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_READER, SMBINTR(dvp)))
149902d09e03SGordon Ross 		return (EINTR);
15004bff34e3Sthurlow 
15014bff34e3Sthurlow 	error = smbfslookup(dvp, nm, vpp, cr, 1, ct);
15024bff34e3Sthurlow 
15034bff34e3Sthurlow 	smbfs_rw_exit(&dnp->r_rwlock);
15044bff34e3Sthurlow 
15054bff34e3Sthurlow 	return (error);
15064bff34e3Sthurlow }
15074bff34e3Sthurlow 
15084bff34e3Sthurlow /* ARGSUSED */
15094bff34e3Sthurlow static int
151002d09e03SGordon Ross smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr,
151102d09e03SGordon Ross 	int cache_ok, caller_context_t *ct)
15124bff34e3Sthurlow {
15134bff34e3Sthurlow 	int		error;
15144bff34e3Sthurlow 	int		supplen; /* supported length */
15154bff34e3Sthurlow 	vnode_t		*vp;
151602d09e03SGordon Ross 	smbnode_t	*np;
15174bff34e3Sthurlow 	smbnode_t	*dnp;
15184bff34e3Sthurlow 	smbmntinfo_t	*smi;
15194bff34e3Sthurlow 	/* struct smb_vc	*vcp; */
152091d632c8Sgwr 	const char	*ill;
15214bff34e3Sthurlow 	const char	*name = (const char *)nm;
15224bff34e3Sthurlow 	int 		nmlen = strlen(nm);
15234bff34e3Sthurlow 	int 		rplen;
15244bff34e3Sthurlow 	struct smb_cred scred;
15254bff34e3Sthurlow 	struct smbfattr fa;
15264bff34e3Sthurlow 
15274bff34e3Sthurlow 	smi = VTOSMI(dvp);
15284bff34e3Sthurlow 	dnp = VTOSMB(dvp);
15294bff34e3Sthurlow 
1530a19609f8Sjv 	ASSERT(curproc->p_zone == smi->smi_zone_ref.zref_zone);
15314bff34e3Sthurlow 
15324bff34e3Sthurlow #ifdef NOT_YET
15334bff34e3Sthurlow 	vcp = SSTOVC(smi->smi_share);
15344bff34e3Sthurlow 
15354bff34e3Sthurlow 	/* XXX: Should compute this once and store it in smbmntinfo_t */
15364bff34e3Sthurlow 	supplen = (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) ? 255 : 12;
15374bff34e3Sthurlow #else
15384bff34e3Sthurlow 	supplen = 255;
15394bff34e3Sthurlow #endif
15404bff34e3Sthurlow 
15414bff34e3Sthurlow 	/*
15424bff34e3Sthurlow 	 * RWlock must be held, either reader or writer.
15434bff34e3Sthurlow 	 * XXX: Can we check without looking directly
15444bff34e3Sthurlow 	 * inside the struct smbfs_rwlock_t?
15454bff34e3Sthurlow 	 */
15464bff34e3Sthurlow 	ASSERT(dnp->r_rwlock.count != 0);
15474bff34e3Sthurlow 
15484bff34e3Sthurlow 	/*
154902d09e03SGordon Ross 	 * If lookup is for "", just return dvp.
155002d09e03SGordon Ross 	 * No need to perform any access checks.
15514bff34e3Sthurlow 	 */
15524bff34e3Sthurlow 	if (nmlen == 0) {
15534bff34e3Sthurlow 		VN_HOLD(dvp);
15544bff34e3Sthurlow 		*vpp = dvp;
15554bff34e3Sthurlow 		return (0);
15564bff34e3Sthurlow 	}
15574bff34e3Sthurlow 
15584bff34e3Sthurlow 	/*
155991d632c8Sgwr 	 * Can't do lookups in non-directories.
15604bff34e3Sthurlow 	 */
15614bff34e3Sthurlow 	if (dvp->v_type != VDIR)
15624bff34e3Sthurlow 		return (ENOTDIR);
15634bff34e3Sthurlow 
156491d632c8Sgwr 	/*
156591d632c8Sgwr 	 * Need search permission in the directory.
156691d632c8Sgwr 	 */
15674bff34e3Sthurlow 	error = smbfs_access(dvp, VEXEC, 0, cr, ct);
15684bff34e3Sthurlow 	if (error)
15694bff34e3Sthurlow 		return (error);
15704bff34e3Sthurlow 
15714bff34e3Sthurlow 	/*
157202d09e03SGordon Ross 	 * If lookup is for ".", just return dvp.
157302d09e03SGordon Ross 	 * Access check was done above.
15744bff34e3Sthurlow 	 */
15754bff34e3Sthurlow 	if (nmlen == 1 && name[0] == '.') {
15764bff34e3Sthurlow 		VN_HOLD(dvp);
15774bff34e3Sthurlow 		*vpp = dvp;
15784bff34e3Sthurlow 		return (0);
15794bff34e3Sthurlow 	}
15804bff34e3Sthurlow 
15814bff34e3Sthurlow 	/*
158291d632c8Sgwr 	 * Now some sanity checks on the name.
158391d632c8Sgwr 	 * First check the length.
15844bff34e3Sthurlow 	 */
158591d632c8Sgwr 	if (nmlen > supplen)
158691d632c8Sgwr 		return (ENAMETOOLONG);
158791d632c8Sgwr 
158891d632c8Sgwr 	/*
158991d632c8Sgwr 	 * Avoid surprises with characters that are
159091d632c8Sgwr 	 * illegal in Windows file names.
159191d632c8Sgwr 	 * Todo: CATIA mappings  XXX
159291d632c8Sgwr 	 */
159391d632c8Sgwr 	ill = illegal_chars;
159491d632c8Sgwr 	if (dnp->n_flag & N_XATTR)
159591d632c8Sgwr 		ill++; /* allow colon */
159691d632c8Sgwr 	if (strpbrk(nm, ill))
159791d632c8Sgwr 		return (EINVAL);
159891d632c8Sgwr 
15994bff34e3Sthurlow 	/*
160002d09e03SGordon Ross 	 * Special handling for lookup of ".."
16014bff34e3Sthurlow 	 *
16024bff34e3Sthurlow 	 * We keep full pathnames (as seen on the server)
16034bff34e3Sthurlow 	 * so we can just trim off the last component to
16044bff34e3Sthurlow 	 * get the full pathname of the parent.  Note:
16054bff34e3Sthurlow 	 * We don't actually copy and modify, but just
16064bff34e3Sthurlow 	 * compute the trimmed length and pass that with
16074bff34e3Sthurlow 	 * the current dir path (not null terminated).
16084bff34e3Sthurlow 	 *
16094bff34e3Sthurlow 	 * We don't go over-the-wire to get attributes
16104bff34e3Sthurlow 	 * for ".." because we know it's a directory,
16114bff34e3Sthurlow 	 * and we can just leave the rest "stale"
16124bff34e3Sthurlow 	 * until someone does a getattr.
16134bff34e3Sthurlow 	 */
16144bff34e3Sthurlow 	if (nmlen == 2 && name[0] == '.' && name[1] == '.') {
16154bff34e3Sthurlow 		if (dvp->v_flag & VROOT) {
16164bff34e3Sthurlow 			/*
16174bff34e3Sthurlow 			 * Already at the root.  This can happen
16184bff34e3Sthurlow 			 * with directory listings at the root,
16194bff34e3Sthurlow 			 * which lookup "." and ".." to get the
16204bff34e3Sthurlow 			 * inode numbers.  Let ".." be the same
16214bff34e3Sthurlow 			 * as "." in the FS root.
16224bff34e3Sthurlow 			 */
16234bff34e3Sthurlow 			VN_HOLD(dvp);
16244bff34e3Sthurlow 			*vpp = dvp;
16254bff34e3Sthurlow 			return (0);
16264bff34e3Sthurlow 		}
16274bff34e3Sthurlow 
162891d632c8Sgwr 		/*
162991d632c8Sgwr 		 * Special case for XATTR directory
163091d632c8Sgwr 		 */
163191d632c8Sgwr 		if (dvp->v_flag & V_XATTRDIR) {
163291d632c8Sgwr 			error = smbfs_xa_parent(dvp, vpp);
163391d632c8Sgwr 			return (error);
163491d632c8Sgwr 		}
163591d632c8Sgwr 
16364bff34e3Sthurlow 		/*
16374bff34e3Sthurlow 		 * Find the parent path length.
16384bff34e3Sthurlow 		 */
16394bff34e3Sthurlow 		rplen = dnp->n_rplen;
16404bff34e3Sthurlow 		ASSERT(rplen > 0);
16414bff34e3Sthurlow 		while (--rplen >= 0) {
16424bff34e3Sthurlow 			if (dnp->n_rpath[rplen] == '\\')
16434bff34e3Sthurlow 				break;
16444bff34e3Sthurlow 		}
164502d09e03SGordon Ross 		if (rplen <= 0) {
16464bff34e3Sthurlow 			/* Found our way to the root. */
16474bff34e3Sthurlow 			vp = SMBTOV(smi->smi_root);
16484bff34e3Sthurlow 			VN_HOLD(vp);
16494bff34e3Sthurlow 			*vpp = vp;
16504bff34e3Sthurlow 			return (0);
16514bff34e3Sthurlow 		}
165202d09e03SGordon Ross 		np = smbfs_node_findcreate(smi,
165302d09e03SGordon Ross 		    dnp->n_rpath, rplen, NULL, 0, 0,
165402d09e03SGordon Ross 		    &smbfs_fattr0); /* force create */
165502d09e03SGordon Ross 		ASSERT(np != NULL);
165602d09e03SGordon Ross 		vp = SMBTOV(np);
16574bff34e3Sthurlow 		vp->v_type = VDIR;
16584bff34e3Sthurlow 
16594bff34e3Sthurlow 		/* Success! */
16604bff34e3Sthurlow 		*vpp = vp;
16614bff34e3Sthurlow 		return (0);
16624bff34e3Sthurlow 	}
16634bff34e3Sthurlow 
16644bff34e3Sthurlow 	/*
166502d09e03SGordon Ross 	 * Normal lookup of a name under this directory.
166602d09e03SGordon Ross 	 * Note we handled "", ".", ".." above.
166702d09e03SGordon Ross 	 */
166802d09e03SGordon Ross 	if (cache_ok) {
166902d09e03SGordon Ross 		/*
167002d09e03SGordon Ross 		 * The caller indicated that it's OK to use a
167102d09e03SGordon Ross 		 * cached result for this lookup, so try to
167202d09e03SGordon Ross 		 * reclaim a node from the smbfs node cache.
167302d09e03SGordon Ross 		 */
167402d09e03SGordon Ross 		error = smbfslookup_cache(dvp, nm, nmlen, &vp, cr);
167502d09e03SGordon Ross 		if (error)
167602d09e03SGordon Ross 			return (error);
167702d09e03SGordon Ross 		if (vp != NULL) {
167802d09e03SGordon Ross 			/* hold taken in lookup_cache */
167902d09e03SGordon Ross 			*vpp = vp;
168002d09e03SGordon Ross 			return (0);
168102d09e03SGordon Ross 		}
168202d09e03SGordon Ross 	}
168302d09e03SGordon Ross 
168402d09e03SGordon Ross 	/*
168502d09e03SGordon Ross 	 * OK, go over-the-wire to get the attributes,
168602d09e03SGordon Ross 	 * then create the node.
16874bff34e3Sthurlow 	 */
1688613a2f6bSGordon Ross 	smb_credinit(&scred, cr);
16894bff34e3Sthurlow 	/* Note: this can allocate a new "name" */
16904bff34e3Sthurlow 	error = smbfs_smb_lookup(dnp, &name, &nmlen, &fa, &scred);
16914bff34e3Sthurlow 	smb_credrele(&scred);
169202d09e03SGordon Ross 	if (error == ENOTDIR) {
169302d09e03SGordon Ross 		/*
169402d09e03SGordon Ross 		 * Lookup failed because this directory was
169502d09e03SGordon Ross 		 * removed or renamed by another client.
169602d09e03SGordon Ross 		 * Remove any cached attributes under it.
169702d09e03SGordon Ross 		 */
169802d09e03SGordon Ross 		smbfs_attrcache_remove(dnp);
169902d09e03SGordon Ross 		smbfs_attrcache_prune(dnp);
170002d09e03SGordon Ross 	}
17014bff34e3Sthurlow 	if (error)
17024bff34e3Sthurlow 		goto out;
17034bff34e3Sthurlow 
17044bff34e3Sthurlow 	error = smbfs_nget(dvp, name, nmlen, &fa, &vp);
17054bff34e3Sthurlow 	if (error)
17064bff34e3Sthurlow 		goto out;
17074bff34e3Sthurlow 
17084bff34e3Sthurlow 	/* Success! */
17094bff34e3Sthurlow 	*vpp = vp;
17104bff34e3Sthurlow 
17114bff34e3Sthurlow out:
17124bff34e3Sthurlow 	/* smbfs_smb_lookup may have allocated name. */
17134bff34e3Sthurlow 	if (name != nm)
17144bff34e3Sthurlow 		smbfs_name_free(name, nmlen);
17154bff34e3Sthurlow 
17164bff34e3Sthurlow 	return (error);
17174bff34e3Sthurlow }
17184bff34e3Sthurlow 
171902d09e03SGordon Ross /*
172002d09e03SGordon Ross  * smbfslookup_cache
172102d09e03SGordon Ross  *
172202d09e03SGordon Ross  * Try to reclaim a node from the smbfs node cache.
172302d09e03SGordon Ross  * Some statistics for DEBUG.
172402d09e03SGordon Ross  *
172502d09e03SGordon Ross  * This mechanism lets us avoid many of the five (or more)
172602d09e03SGordon Ross  * OtW lookup calls per file seen with "ls -l" if we search
172702d09e03SGordon Ross  * the smbfs node cache for recently inactive(ated) nodes.
172802d09e03SGordon Ross  */
172991d632c8Sgwr #ifdef DEBUG
173002d09e03SGordon Ross int smbfs_lookup_cache_calls = 0;
173102d09e03SGordon Ross int smbfs_lookup_cache_error = 0;
173202d09e03SGordon Ross int smbfs_lookup_cache_miss = 0;
173302d09e03SGordon Ross int smbfs_lookup_cache_stale = 0;
173402d09e03SGordon Ross int smbfs_lookup_cache_hits = 0;
173502d09e03SGordon Ross #endif /* DEBUG */
173691d632c8Sgwr 
173791d632c8Sgwr /* ARGSUSED */
173891d632c8Sgwr static int
173902d09e03SGordon Ross smbfslookup_cache(vnode_t *dvp, char *nm, int nmlen,
174002d09e03SGordon Ross 	vnode_t **vpp, cred_t *cr)
174191d632c8Sgwr {
174291d632c8Sgwr 	struct vattr va;
174391d632c8Sgwr 	smbnode_t *dnp;
174402d09e03SGordon Ross 	smbnode_t *np;
174502d09e03SGordon Ross 	vnode_t *vp;
174602d09e03SGordon Ross 	int error;
174702d09e03SGordon Ross 	char sep;
174891d632c8Sgwr 
174991d632c8Sgwr 	dnp = VTOSMB(dvp);
175002d09e03SGordon Ross 	*vpp = NULL;
175191d632c8Sgwr 
175202d09e03SGordon Ross #ifdef DEBUG
175302d09e03SGordon Ross 	smbfs_lookup_cache_calls++;
175402d09e03SGordon Ross #endif
175591d632c8Sgwr 
175691d632c8Sgwr 	/*
175702d09e03SGordon Ross 	 * First make sure we can get attributes for the
175802d09e03SGordon Ross 	 * directory.  Cached attributes are OK here.
175902d09e03SGordon Ross 	 * If we removed or renamed the directory, this
176002d09e03SGordon Ross 	 * will return ENOENT.  If someone else removed
176102d09e03SGordon Ross 	 * this directory or file, we'll find out when we
176202d09e03SGordon Ross 	 * try to open or get attributes.
176391d632c8Sgwr 	 */
176402d09e03SGordon Ross 	va.va_mask = AT_TYPE | AT_MODE;
176502d09e03SGordon Ross 	error = smbfsgetattr(dvp, &va, cr);
176602d09e03SGordon Ross 	if (error) {
176791d632c8Sgwr #ifdef DEBUG
176802d09e03SGordon Ross 		smbfs_lookup_cache_error++;
176991d632c8Sgwr #endif
177002d09e03SGordon Ross 		return (error);
177102d09e03SGordon Ross 	}
177202d09e03SGordon Ross 
177302d09e03SGordon Ross 	/*
177402d09e03SGordon Ross 	 * Passing NULL smbfattr here so we will
177502d09e03SGordon Ross 	 * just look, not create.
177602d09e03SGordon Ross 	 */
177702d09e03SGordon Ross 	sep = SMBFS_DNP_SEP(dnp);
177802d09e03SGordon Ross 	np = smbfs_node_findcreate(dnp->n_mount,
177902d09e03SGordon Ross 	    dnp->n_rpath, dnp->n_rplen,
178002d09e03SGordon Ross 	    nm, nmlen, sep, NULL);
178102d09e03SGordon Ross 	if (np == NULL) {
178291d632c8Sgwr #ifdef DEBUG
178302d09e03SGordon Ross 		smbfs_lookup_cache_miss++;
178491d632c8Sgwr #endif
178502d09e03SGordon Ross 		return (0);
178602d09e03SGordon Ross 	}
178702d09e03SGordon Ross 
178802d09e03SGordon Ross 	/*
178902d09e03SGordon Ross 	 * Found it.  Attributes still valid?
179002d09e03SGordon Ross 	 */
179102d09e03SGordon Ross 	vp = SMBTOV(np);
179202d09e03SGordon Ross 	if (np->r_attrtime <= gethrtime()) {
179302d09e03SGordon Ross 		/* stale */
179491d632c8Sgwr #ifdef DEBUG
179502d09e03SGordon Ross 		smbfs_lookup_cache_stale++;
179691d632c8Sgwr #endif
179702d09e03SGordon Ross 		VN_RELE(vp);
179802d09e03SGordon Ross 		return (0);
179991d632c8Sgwr 	}
180002d09e03SGordon Ross 
180102d09e03SGordon Ross 	/*
180202d09e03SGordon Ross 	 * Success!
180302d09e03SGordon Ross 	 * Caller gets hold from smbfs_node_findcreate
180402d09e03SGordon Ross 	 */
180591d632c8Sgwr #ifdef DEBUG
180602d09e03SGordon Ross 	smbfs_lookup_cache_hits++;
180791d632c8Sgwr #endif
180802d09e03SGordon Ross 	*vpp = vp;
180991d632c8Sgwr 	return (0);
181091d632c8Sgwr }
181191d632c8Sgwr 
18124bff34e3Sthurlow /*
18134bff34e3Sthurlow  * XXX
18144bff34e3Sthurlow  * vsecattr_t is new to build 77, and we need to eventually support
18154bff34e3Sthurlow  * it in order to create an ACL when an object is created.
18164bff34e3Sthurlow  *
18174bff34e3Sthurlow  * This op should support the new FIGNORECASE flag for case-insensitive
18184bff34e3Sthurlow  * lookups, per PSARC 2007/244.
18194bff34e3Sthurlow  */
18204bff34e3Sthurlow /* ARGSUSED */
18214bff34e3Sthurlow static int
18224bff34e3Sthurlow smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
18234bff34e3Sthurlow 	int mode, vnode_t **vpp, cred_t *cr, int lfaware, caller_context_t *ct,
18244bff34e3Sthurlow 	vsecattr_t *vsecp)
18254bff34e3Sthurlow {
18264bff34e3Sthurlow 	int		error;
18274bff34e3Sthurlow 	int		cerror;
18284bff34e3Sthurlow 	vfs_t		*vfsp;
18294bff34e3Sthurlow 	vnode_t		*vp;
18304bff34e3Sthurlow #ifdef NOT_YET
18314bff34e3Sthurlow 	smbnode_t	*np;
18324bff34e3Sthurlow #endif
18334bff34e3Sthurlow 	smbnode_t	*dnp;
18344bff34e3Sthurlow 	smbmntinfo_t	*smi;
18354bff34e3Sthurlow 	struct vattr	vattr;
18364bff34e3Sthurlow 	struct smbfattr	fattr;
18374bff34e3Sthurlow 	struct smb_cred	scred;
18384bff34e3Sthurlow 	const char *name = (const char *)nm;
18394bff34e3Sthurlow 	int		nmlen = strlen(nm);
18404bff34e3Sthurlow 	uint32_t	disp;
18414bff34e3Sthurlow 	uint16_t	fid;
184291d632c8Sgwr 	int		xattr;
18434bff34e3Sthurlow 
18444bff34e3Sthurlow 	vfsp = dvp->v_vfsp;
18454bff34e3Sthurlow 	smi = VFTOSMI(vfsp);
18464bff34e3Sthurlow 	dnp = VTOSMB(dvp);
18474bff34e3Sthurlow 	vp = NULL;
18484bff34e3Sthurlow 
1849a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
18504bff34e3Sthurlow 		return (EPERM);
18514bff34e3Sthurlow 
18524bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
18534bff34e3Sthurlow 		return (EIO);
18544bff34e3Sthurlow 
18554bff34e3Sthurlow 	/*
18564bff34e3Sthurlow 	 * Note: this may break mknod(2) calls to create a directory,
18574bff34e3Sthurlow 	 * but that's obscure use.  Some other filesystems do this.
18584bff34e3Sthurlow 	 * XXX: Later, redirect VDIR type here to _mkdir.
18594bff34e3Sthurlow 	 */
18604bff34e3Sthurlow 	if (va->va_type != VREG)
18614bff34e3Sthurlow 		return (EINVAL);
18624bff34e3Sthurlow 
18634bff34e3Sthurlow 	/*
18644bff34e3Sthurlow 	 * If the pathname is "", just use dvp, no checks.
18654bff34e3Sthurlow 	 * Do this outside of the rwlock (like zfs).
18664bff34e3Sthurlow 	 */
18674bff34e3Sthurlow 	if (nmlen == 0) {
18684bff34e3Sthurlow 		VN_HOLD(dvp);
18694bff34e3Sthurlow 		*vpp = dvp;
18704bff34e3Sthurlow 		return (0);
18714bff34e3Sthurlow 	}
18724bff34e3Sthurlow 
18734bff34e3Sthurlow 	/* Don't allow "." or ".." through here. */
18744bff34e3Sthurlow 	if ((nmlen == 1 && name[0] == '.') ||
18754bff34e3Sthurlow 	    (nmlen == 2 && name[0] == '.' && name[1] == '.'))
18764bff34e3Sthurlow 		return (EISDIR);
18774bff34e3Sthurlow 
18784bff34e3Sthurlow 	/*
18794bff34e3Sthurlow 	 * We make a copy of the attributes because the caller does not
18804bff34e3Sthurlow 	 * expect us to change what va points to.
18814bff34e3Sthurlow 	 */
18824bff34e3Sthurlow 	vattr = *va;
18834bff34e3Sthurlow 
18844bff34e3Sthurlow 	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
18854bff34e3Sthurlow 		return (EINTR);
1886613a2f6bSGordon Ross 	smb_credinit(&scred, cr);
18874bff34e3Sthurlow 
18884bff34e3Sthurlow 	/*
18894bff34e3Sthurlow 	 * NFS needs to go over the wire, just to be sure whether the
189002d09e03SGordon Ross 	 * file exists or not.  Using a cached result is dangerous in
18914bff34e3Sthurlow 	 * this case when making a decision regarding existence.
18924bff34e3Sthurlow 	 *
18934bff34e3Sthurlow 	 * The SMB protocol does NOT really need to go OTW here
18944bff34e3Sthurlow 	 * thanks to the expressive NTCREATE disposition values.
18954bff34e3Sthurlow 	 * Unfortunately, to do Unix access checks correctly,
18964bff34e3Sthurlow 	 * we need to know if the object already exists.
18974bff34e3Sthurlow 	 * When the object does not exist, we need VWRITE on
18984bff34e3Sthurlow 	 * the directory.  Note: smbfslookup() checks VEXEC.
18994bff34e3Sthurlow 	 */
19004bff34e3Sthurlow 	error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
19014bff34e3Sthurlow 	if (error == 0) {
19024bff34e3Sthurlow 		/*
190342645588SGordon Ross 		 * The file already exists.  Error?
190442645588SGordon Ross 		 * NB: have a hold from smbfslookup
19054bff34e3Sthurlow 		 */
19064bff34e3Sthurlow 		if (exclusive == EXCL) {
19074bff34e3Sthurlow 			error = EEXIST;
190842645588SGordon Ross 			VN_RELE(vp);
19094bff34e3Sthurlow 			goto out;
19104bff34e3Sthurlow 		}
19114bff34e3Sthurlow 		/*
19124bff34e3Sthurlow 		 * Verify requested access.
19134bff34e3Sthurlow 		 */
19144bff34e3Sthurlow 		error = smbfs_access(vp, mode, 0, cr, ct);
191542645588SGordon Ross 		if (error) {
191642645588SGordon Ross 			VN_RELE(vp);
19174bff34e3Sthurlow 			goto out;
191842645588SGordon Ross 		}
19194bff34e3Sthurlow 
19204bff34e3Sthurlow 		/*
19214bff34e3Sthurlow 		 * Truncate (if requested).
19224bff34e3Sthurlow 		 */
19234bff34e3Sthurlow 		if ((vattr.va_mask & AT_SIZE) && vattr.va_size == 0) {
19244bff34e3Sthurlow 			vattr.va_mask = AT_SIZE;
19254bff34e3Sthurlow 			error = smbfssetattr(vp, &vattr, 0, cr);
192642645588SGordon Ross 			if (error) {
192742645588SGordon Ross 				VN_RELE(vp);
19284bff34e3Sthurlow 				goto out;
192942645588SGordon Ross 			}
19304bff34e3Sthurlow 		}
19314bff34e3Sthurlow 		/* Success! */
19324bff34e3Sthurlow #ifdef NOT_YET
19334bff34e3Sthurlow 		vnevent_create(vp, ct);
19344bff34e3Sthurlow #endif
19354bff34e3Sthurlow 		*vpp = vp;
19364bff34e3Sthurlow 		goto out;
19374bff34e3Sthurlow 	}
19384bff34e3Sthurlow 
19394bff34e3Sthurlow 	/*
19404bff34e3Sthurlow 	 * The file did not exist.  Need VWRITE in the directory.
19414bff34e3Sthurlow 	 */
19424bff34e3Sthurlow 	error = smbfs_access(dvp, VWRITE, 0, cr, ct);
19434bff34e3Sthurlow 	if (error)
19444bff34e3Sthurlow 		goto out;
19454bff34e3Sthurlow 
19464bff34e3Sthurlow 	/*
19474bff34e3Sthurlow 	 * Now things get tricky.  We also need to check the
19484bff34e3Sthurlow 	 * requested open mode against the file we may create.
19494bff34e3Sthurlow 	 * See comments at smbfs_access_rwx
19504bff34e3Sthurlow 	 */
19514bff34e3Sthurlow 	error = smbfs_access_rwx(vfsp, VREG, mode, cr);
19524bff34e3Sthurlow 	if (error)
19534bff34e3Sthurlow 		goto out;
19544bff34e3Sthurlow 
19554bff34e3Sthurlow 	/*
19564bff34e3Sthurlow 	 * Now the code derived from Darwin,
19574bff34e3Sthurlow 	 * but with greater use of NT_CREATE
19584bff34e3Sthurlow 	 * disposition options.  Much changed.
19594bff34e3Sthurlow 	 *
19604bff34e3Sthurlow 	 * Create (or open) a new child node.
19614bff34e3Sthurlow 	 * Note we handled "." and ".." above.
19624bff34e3Sthurlow 	 */
19634bff34e3Sthurlow 
19644bff34e3Sthurlow 	if (exclusive == EXCL)
19654bff34e3Sthurlow 		disp = NTCREATEX_DISP_CREATE;
19664bff34e3Sthurlow 	else {
19674bff34e3Sthurlow 		/* Truncate regular files if requested. */
19684bff34e3Sthurlow 		if ((va->va_type == VREG) &&
19694bff34e3Sthurlow 		    (va->va_mask & AT_SIZE) &&
19704bff34e3Sthurlow 		    (va->va_size == 0))
19714bff34e3Sthurlow 			disp = NTCREATEX_DISP_OVERWRITE_IF;
19724bff34e3Sthurlow 		else
19734bff34e3Sthurlow 			disp = NTCREATEX_DISP_OPEN_IF;
19744bff34e3Sthurlow 	}
197591d632c8Sgwr 	xattr = (dnp->n_flag & N_XATTR) ? 1 : 0;
197602d09e03SGordon Ross 	error = smbfs_smb_create(dnp,
197702d09e03SGordon Ross 	    name, nmlen, xattr,
197802d09e03SGordon Ross 	    disp, &scred, &fid);
19794bff34e3Sthurlow 	if (error)
19804bff34e3Sthurlow 		goto out;
19814bff34e3Sthurlow 
19824bff34e3Sthurlow 	/*
19834bff34e3Sthurlow 	 * XXX: Missing some code here to deal with
19844bff34e3Sthurlow 	 * the case where we opened an existing file,
19854bff34e3Sthurlow 	 * it's size is larger than 32-bits, and we're
19864bff34e3Sthurlow 	 * setting the size from a process that's not
19874bff34e3Sthurlow 	 * aware of large file offsets.  i.e.
19884bff34e3Sthurlow 	 * from the NFS3 code:
19894bff34e3Sthurlow 	 */
19904bff34e3Sthurlow #if NOT_YET /* XXX */
19914bff34e3Sthurlow 	if ((vattr.va_mask & AT_SIZE) &&
19924bff34e3Sthurlow 	    vp->v_type == VREG) {
19934bff34e3Sthurlow 		np = VTOSMB(vp);
19944bff34e3Sthurlow 		/*
19954bff34e3Sthurlow 		 * Check here for large file handled
19964bff34e3Sthurlow 		 * by LF-unaware process (as
19974bff34e3Sthurlow 		 * ufs_create() does)
19984bff34e3Sthurlow 		 */
19994bff34e3Sthurlow 		if (!(lfaware & FOFFMAX)) {
20004bff34e3Sthurlow 			mutex_enter(&np->r_statelock);
20014bff34e3Sthurlow 			if (np->r_size > MAXOFF32_T)
20024bff34e3Sthurlow 				error = EOVERFLOW;
20034bff34e3Sthurlow 			mutex_exit(&np->r_statelock);
20044bff34e3Sthurlow 		}
20054bff34e3Sthurlow 		if (!error) {
20064bff34e3Sthurlow 			vattr.va_mask = AT_SIZE;
20074bff34e3Sthurlow 			error = smbfssetattr(vp,
20084bff34e3Sthurlow 			    &vattr, 0, cr);
20094bff34e3Sthurlow 		}
20104bff34e3Sthurlow 	}
20114bff34e3Sthurlow #endif /* XXX */
20124bff34e3Sthurlow 	/*
20134bff34e3Sthurlow 	 * Should use the fid to get/set the size
20144bff34e3Sthurlow 	 * while we have it opened here.  See above.
20154bff34e3Sthurlow 	 */
20164bff34e3Sthurlow 
20174bff34e3Sthurlow 	cerror = smbfs_smb_close(smi->smi_share, fid, NULL, &scred);
20184bff34e3Sthurlow 	if (cerror)
201902d09e03SGordon Ross 		SMBVDEBUG("error %d closing %s\\%s\n",
20204bff34e3Sthurlow 		    cerror, dnp->n_rpath, name);
20214bff34e3Sthurlow 
20224bff34e3Sthurlow 	/*
20234bff34e3Sthurlow 	 * In the open case, the name may differ a little
20244bff34e3Sthurlow 	 * from what we passed to create (case, etc.)
20254bff34e3Sthurlow 	 * so call lookup to get the (opened) name.
20264bff34e3Sthurlow 	 *
20274bff34e3Sthurlow 	 * XXX: Could avoid this extra lookup if the
20284bff34e3Sthurlow 	 * "createact" result from NT_CREATE says we
20294bff34e3Sthurlow 	 * created the object.
20304bff34e3Sthurlow 	 */
20314bff34e3Sthurlow 	error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred);
20324bff34e3Sthurlow 	if (error)
20334bff34e3Sthurlow 		goto out;
20344bff34e3Sthurlow 
20354bff34e3Sthurlow 	/* update attr and directory cache */
20364bff34e3Sthurlow 	smbfs_attr_touchdir(dnp);
20374bff34e3Sthurlow 
20384bff34e3Sthurlow 	error = smbfs_nget(dvp, name, nmlen, &fattr, &vp);
20394bff34e3Sthurlow 	if (error)
20404bff34e3Sthurlow 		goto out;
20414bff34e3Sthurlow 
204291d632c8Sgwr 	/* XXX invalidate pages if we truncated? */
204391d632c8Sgwr 
20444bff34e3Sthurlow 	/* Success! */
20454bff34e3Sthurlow 	*vpp = vp;
20464bff34e3Sthurlow 	error = 0;
20474bff34e3Sthurlow 
20484bff34e3Sthurlow out:
20494bff34e3Sthurlow 	smb_credrele(&scred);
205002d09e03SGordon Ross 	smbfs_rw_exit(&dnp->r_rwlock);
20514bff34e3Sthurlow 	if (name != nm)
20524bff34e3Sthurlow 		smbfs_name_free(name, nmlen);
20534bff34e3Sthurlow 	return (error);
20544bff34e3Sthurlow }
20554bff34e3Sthurlow 
20564bff34e3Sthurlow /*
20574bff34e3Sthurlow  * XXX
20584bff34e3Sthurlow  * This op should support the new FIGNORECASE flag for case-insensitive
20594bff34e3Sthurlow  * lookups, per PSARC 2007/244.
20604bff34e3Sthurlow  */
20614bff34e3Sthurlow /* ARGSUSED */
20624bff34e3Sthurlow static int
20634bff34e3Sthurlow smbfs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct,
20644bff34e3Sthurlow 	int flags)
20654bff34e3Sthurlow {
20664bff34e3Sthurlow 	struct smb_cred	scred;
2067*ff1e230cSjilinxpd 	vnode_t		*vp = NULL;
2068*ff1e230cSjilinxpd 	smbnode_t	*dnp = VTOSMB(dvp);
2069*ff1e230cSjilinxpd 	smbmntinfo_t	*smi = VTOSMI(dvp);
2070*ff1e230cSjilinxpd 	int		error;
20714bff34e3Sthurlow 
2072a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
20734bff34e3Sthurlow 		return (EPERM);
20744bff34e3Sthurlow 
20754bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
20764bff34e3Sthurlow 		return (EIO);
20774bff34e3Sthurlow 
20784bff34e3Sthurlow 	/*
20794bff34e3Sthurlow 	 * Verify access to the dirctory.
20804bff34e3Sthurlow 	 */
20814bff34e3Sthurlow 	error = smbfs_access(dvp, VWRITE|VEXEC, 0, cr, ct);
20824bff34e3Sthurlow 	if (error)
2083*ff1e230cSjilinxpd 		return (error);
2084*ff1e230cSjilinxpd 
2085*ff1e230cSjilinxpd 	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
2086*ff1e230cSjilinxpd 		return (EINTR);
2087*ff1e230cSjilinxpd 	smb_credinit(&scred, cr);
2088*ff1e230cSjilinxpd 
2089*ff1e230cSjilinxpd 	/* Lookup the file to remove. */
2090*ff1e230cSjilinxpd 	error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
2091*ff1e230cSjilinxpd 	if (error == 0) {
2092*ff1e230cSjilinxpd 		/*
2093*ff1e230cSjilinxpd 		 * Do the real remove work
2094*ff1e230cSjilinxpd 		 */
2095*ff1e230cSjilinxpd 		error = smbfsremove(dvp, vp, &scred, flags);
2096*ff1e230cSjilinxpd 		VN_RELE(vp);
2097*ff1e230cSjilinxpd 	}
2098*ff1e230cSjilinxpd 
2099*ff1e230cSjilinxpd 	smb_credrele(&scred);
2100*ff1e230cSjilinxpd 	smbfs_rw_exit(&dnp->r_rwlock);
2101*ff1e230cSjilinxpd 
2102*ff1e230cSjilinxpd 	return (error);
2103*ff1e230cSjilinxpd }
2104*ff1e230cSjilinxpd 
2105*ff1e230cSjilinxpd /*
2106*ff1e230cSjilinxpd  * smbfsremove does the real work of removing in SMBFS
2107*ff1e230cSjilinxpd  * Caller has done dir access checks etc.
2108*ff1e230cSjilinxpd  *
2109*ff1e230cSjilinxpd  * The normal way to delete a file over SMB is open it (with DELETE access),
2110*ff1e230cSjilinxpd  * set the "delete-on-close" flag, and close the file.  The problem for Unix
2111*ff1e230cSjilinxpd  * applications is that they expect the file name to be gone once the unlink
2112*ff1e230cSjilinxpd  * completes, and the SMB server does not actually delete the file until ALL
2113*ff1e230cSjilinxpd  * opens of that file are closed.  We can't assume our open handles are the
2114*ff1e230cSjilinxpd  * only open handles on a file we're deleting, so to be safe we'll try to
2115*ff1e230cSjilinxpd  * rename the file to a temporary name and then set delete-on-close.  If we
2116*ff1e230cSjilinxpd  * fail to set delete-on-close (i.e. because other opens prevent it) then
2117*ff1e230cSjilinxpd  * undo the changes we made and give up with EBUSY.  Note that we might have
2118*ff1e230cSjilinxpd  * permission to delete a file but lack permission to rename, so we want to
2119*ff1e230cSjilinxpd  * continue in cases where rename fails.  As an optimization, only do the
2120*ff1e230cSjilinxpd  * rename when we have the file open.
2121*ff1e230cSjilinxpd  *
2122*ff1e230cSjilinxpd  * This is similar to what NFS does when deleting a file that has local opens,
2123*ff1e230cSjilinxpd  * but thanks to SMB delete-on-close, we don't need to keep track of when the
2124*ff1e230cSjilinxpd  * last local open goes away and send a delete.  The server does that for us.
2125*ff1e230cSjilinxpd  */
2126*ff1e230cSjilinxpd /* ARGSUSED */
2127*ff1e230cSjilinxpd static int
2128*ff1e230cSjilinxpd smbfsremove(vnode_t *dvp, vnode_t *vp, struct smb_cred *scred,
2129*ff1e230cSjilinxpd     int flags)
2130*ff1e230cSjilinxpd {
2131*ff1e230cSjilinxpd 	smbnode_t	*dnp = VTOSMB(dvp);
2132*ff1e230cSjilinxpd 	smbnode_t	*np = VTOSMB(vp);
2133*ff1e230cSjilinxpd 	char		*tmpname = NULL;
2134*ff1e230cSjilinxpd 	int		tnlen;
2135*ff1e230cSjilinxpd 	int		error;
2136*ff1e230cSjilinxpd 	unsigned short	fid;
2137*ff1e230cSjilinxpd 	boolean_t	have_fid = B_FALSE;
2138*ff1e230cSjilinxpd 	boolean_t	renamed = B_FALSE;
21394bff34e3Sthurlow 
21404bff34e3Sthurlow 	/*
2141*ff1e230cSjilinxpd 	 * The dvp RWlock must be held as writer.
21424bff34e3Sthurlow 	 */
2143*ff1e230cSjilinxpd 	ASSERT(dnp->r_rwlock.owner == curthread);
21444bff34e3Sthurlow 
2145*ff1e230cSjilinxpd 	/* Never allow link/unlink directories on SMB. */
2146*ff1e230cSjilinxpd 	if (vp->v_type == VDIR)
2147*ff1e230cSjilinxpd 		return (EPERM);
2148*ff1e230cSjilinxpd 
2149*ff1e230cSjilinxpd 	/* Shared lock for n_fid use in smbfs_smb_setdisp etc. */
2150*ff1e230cSjilinxpd 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
2151*ff1e230cSjilinxpd 		return (EINTR);
2152*ff1e230cSjilinxpd 
2153*ff1e230cSjilinxpd 	/* Force lookup to go OtW */
2154*ff1e230cSjilinxpd 	smbfs_attrcache_remove(np);
2155*ff1e230cSjilinxpd 
2156*ff1e230cSjilinxpd 	/*
2157*ff1e230cSjilinxpd 	 * Get a file handle with delete access.
2158*ff1e230cSjilinxpd 	 * Close this FID before return.
2159*ff1e230cSjilinxpd 	 */
2160*ff1e230cSjilinxpd 	error = smbfs_smb_tmpopen(np, STD_RIGHT_DELETE_ACCESS,
2161*ff1e230cSjilinxpd 	    scred, &fid);
2162*ff1e230cSjilinxpd 	if (error) {
2163*ff1e230cSjilinxpd 		SMBVDEBUG("error %d opening %s\n",
2164*ff1e230cSjilinxpd 		    error, np->n_rpath);
21654bff34e3Sthurlow 		goto out;
21664bff34e3Sthurlow 	}
2167*ff1e230cSjilinxpd 	have_fid = B_TRUE;
21684bff34e3Sthurlow 
21694bff34e3Sthurlow 	/*
2170*ff1e230cSjilinxpd 	 * If we have the file open, try to rename it to a temporary name.
2171*ff1e230cSjilinxpd 	 * If we can't rename, continue on and try setting DoC anyway.
21724bff34e3Sthurlow 	 */
217302d09e03SGordon Ross 	if ((vp->v_count > 1) && (np->n_fidrefs > 0)) {
2174*ff1e230cSjilinxpd 		tmpname = kmem_alloc(MAXNAMELEN, KM_SLEEP);
2175*ff1e230cSjilinxpd 		tnlen = smbfs_newname(tmpname, MAXNAMELEN);
2176*ff1e230cSjilinxpd 		error = smbfs_smb_t2rename(np, tmpname, tnlen, scred, fid, 0);
2177*ff1e230cSjilinxpd 		if (error != 0) {
2178*ff1e230cSjilinxpd 			SMBVDEBUG("error %d renaming %s -> %s\n",
2179*ff1e230cSjilinxpd 				  error, np->n_rpath, tmpname);
2180*ff1e230cSjilinxpd 			/* Keep going without the rename. */
2181*ff1e230cSjilinxpd 		} else {
2182*ff1e230cSjilinxpd 			renamed = B_TRUE;
2183*ff1e230cSjilinxpd 		}
2184*ff1e230cSjilinxpd 	}
21854bff34e3Sthurlow 
2186*ff1e230cSjilinxpd 	/*
2187*ff1e230cSjilinxpd 	 * Mark the file as delete-on-close.  If we can't,
2188*ff1e230cSjilinxpd 	 * undo what we did and err out.
2189*ff1e230cSjilinxpd 	 */
2190*ff1e230cSjilinxpd 	error = smbfs_smb_setdisp(np, fid, 1, scred);
2191*ff1e230cSjilinxpd 	if (error != 0) {
2192*ff1e230cSjilinxpd 		SMBVDEBUG("error %d setting DoC on %s\n",
2193*ff1e230cSjilinxpd 		    error, np->n_rpath);
219402d09e03SGordon Ross 		/*
2195*ff1e230cSjilinxpd 		 * Failed to set DoC. If we renamed, undo that.
2196*ff1e230cSjilinxpd 		 * Need np->n_rpath relative to parent (dnp).
2197*ff1e230cSjilinxpd 		 * Use parent path name length plus one for
2198*ff1e230cSjilinxpd 		 * the separator ('/' or ':')
219902d09e03SGordon Ross 		 */
2200*ff1e230cSjilinxpd 		if (renamed) {
2201*ff1e230cSjilinxpd 			char *oldname;
2202*ff1e230cSjilinxpd 			int oldnlen;
2203*ff1e230cSjilinxpd 			int err2;
2204*ff1e230cSjilinxpd 
2205*ff1e230cSjilinxpd 			oldname = np->n_rpath + (dnp->n_rplen + 1);
2206*ff1e230cSjilinxpd 			oldnlen = np->n_rplen - (dnp->n_rplen + 1);
2207*ff1e230cSjilinxpd 			err2 = smbfs_smb_t2rename(np, oldname, oldnlen,
2208*ff1e230cSjilinxpd 			    scred, fid, 0);
2209*ff1e230cSjilinxpd 			SMBVDEBUG("error %d un-renaming %s -> %s\n",
2210*ff1e230cSjilinxpd 			  err2, tmpname, np->n_rpath);
221102d09e03SGordon Ross 		}
2212*ff1e230cSjilinxpd 		error = EBUSY;
2213*ff1e230cSjilinxpd 		goto out;
22144bff34e3Sthurlow 	}
2215*ff1e230cSjilinxpd 	/* Done! */
2216*ff1e230cSjilinxpd 	smbfs_attrcache_prune(np);
22174bff34e3Sthurlow 
22184bff34e3Sthurlow out:
2219*ff1e230cSjilinxpd 	if (tmpname != NULL)
2220*ff1e230cSjilinxpd 		kmem_free(tmpname, MAXNAMELEN);
2221*ff1e230cSjilinxpd 
2222*ff1e230cSjilinxpd 	if (have_fid)
2223*ff1e230cSjilinxpd 		(void) smbfs_smb_tmpclose(np, fid, scred);
2224*ff1e230cSjilinxpd 	smbfs_rw_exit(&np->r_lkserlock);
2225*ff1e230cSjilinxpd 
2226*ff1e230cSjilinxpd 	if (error == 0) {
2227*ff1e230cSjilinxpd 		/* Keep lookup from finding this node anymore. */
2228*ff1e230cSjilinxpd 		smbfs_rmhash(np);
2229*ff1e230cSjilinxpd 	}
22304bff34e3Sthurlow 
22314bff34e3Sthurlow 	return (error);
22324bff34e3Sthurlow }
22334bff34e3Sthurlow 
22344bff34e3Sthurlow 
22354bff34e3Sthurlow /*
22364bff34e3Sthurlow  * XXX
22374bff34e3Sthurlow  * This op should support the new FIGNORECASE flag for case-insensitive
22384bff34e3Sthurlow  * lookups, per PSARC 2007/244.
22394bff34e3Sthurlow  */
22404bff34e3Sthurlow /* ARGSUSED */
22414bff34e3Sthurlow static int
22424bff34e3Sthurlow smbfs_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
22434bff34e3Sthurlow 	caller_context_t *ct, int flags)
22444bff34e3Sthurlow {
2245*ff1e230cSjilinxpd 	struct smb_cred	scred;
2246*ff1e230cSjilinxpd 	smbnode_t	*odnp = VTOSMB(odvp);
2247*ff1e230cSjilinxpd 	smbnode_t	*ndnp = VTOSMB(ndvp);
2248*ff1e230cSjilinxpd 	vnode_t		*ovp;
2249*ff1e230cSjilinxpd 	int error;
22504bff34e3Sthurlow 
2251a19609f8Sjv 	if (curproc->p_zone != VTOSMI(odvp)->smi_zone_ref.zref_zone ||
2252a19609f8Sjv 	    curproc->p_zone != VTOSMI(ndvp)->smi_zone_ref.zref_zone)
22534bff34e3Sthurlow 		return (EPERM);
22544bff34e3Sthurlow 
22554bff34e3Sthurlow 	if (VTOSMI(odvp)->smi_flags & SMI_DEAD ||
22564bff34e3Sthurlow 	    VTOSMI(ndvp)->smi_flags & SMI_DEAD ||
22574bff34e3Sthurlow 	    odvp->v_vfsp->vfs_flag & VFS_UNMOUNTED ||
22584bff34e3Sthurlow 	    ndvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
22594bff34e3Sthurlow 		return (EIO);
22604bff34e3Sthurlow 
22614bff34e3Sthurlow 	if (strcmp(onm, ".") == 0 || strcmp(onm, "..") == 0 ||
22624bff34e3Sthurlow 	    strcmp(nnm, ".") == 0 || strcmp(nnm, "..") == 0)
22634bff34e3Sthurlow 		return (EINVAL);
22644bff34e3Sthurlow 
22654bff34e3Sthurlow 	/*
22664bff34e3Sthurlow 	 * Check that everything is on the same filesystem.
22674bff34e3Sthurlow 	 * vn_rename checks the fsid's, but in case we don't
22684bff34e3Sthurlow 	 * fill those in correctly, check here too.
22694bff34e3Sthurlow 	 */
22704bff34e3Sthurlow 	if (odvp->v_vfsp != ndvp->v_vfsp)
22714bff34e3Sthurlow 		return (EXDEV);
22724bff34e3Sthurlow 
2273*ff1e230cSjilinxpd 	/*
2274*ff1e230cSjilinxpd 	 * Need write access on source and target.
2275*ff1e230cSjilinxpd 	 * Server takes care of most checks.
2276*ff1e230cSjilinxpd 	 */
2277*ff1e230cSjilinxpd 	error = smbfs_access(odvp, VWRITE|VEXEC, 0, cr, ct);
2278*ff1e230cSjilinxpd 	if (error)
2279*ff1e230cSjilinxpd 		return (error);
2280*ff1e230cSjilinxpd 	if (odvp != ndvp) {
2281*ff1e230cSjilinxpd 		error = smbfs_access(ndvp, VWRITE, 0, cr, ct);
2282*ff1e230cSjilinxpd 		if (error)
2283*ff1e230cSjilinxpd 			return (error);
2284*ff1e230cSjilinxpd 	}
22854bff34e3Sthurlow 
22864bff34e3Sthurlow 	/*
2287*ff1e230cSjilinxpd 	 * Need to lock both old/new dirs as writer.
2288*ff1e230cSjilinxpd 	 *
22894bff34e3Sthurlow 	 * Avoid deadlock here on old vs new directory nodes
22904bff34e3Sthurlow 	 * by always taking the locks in order of address.
22914bff34e3Sthurlow 	 * The order is arbitrary, but must be consistent.
22924bff34e3Sthurlow 	 */
22934bff34e3Sthurlow 	if (odnp < ndnp) {
22944bff34e3Sthurlow 		if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER,
22954bff34e3Sthurlow 		    SMBINTR(odvp)))
22964bff34e3Sthurlow 			return (EINTR);
22974bff34e3Sthurlow 		if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER,
22984bff34e3Sthurlow 		    SMBINTR(ndvp))) {
22994bff34e3Sthurlow 			smbfs_rw_exit(&odnp->r_rwlock);
23004bff34e3Sthurlow 			return (EINTR);
23014bff34e3Sthurlow 		}
23024bff34e3Sthurlow 	} else {
23034bff34e3Sthurlow 		if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER,
23044bff34e3Sthurlow 		    SMBINTR(ndvp)))
23054bff34e3Sthurlow 			return (EINTR);
23064bff34e3Sthurlow 		if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER,
23074bff34e3Sthurlow 		    SMBINTR(odvp))) {
23084bff34e3Sthurlow 			smbfs_rw_exit(&ndnp->r_rwlock);
23094bff34e3Sthurlow 			return (EINTR);
23104bff34e3Sthurlow 		}
23114bff34e3Sthurlow 	}
231202d09e03SGordon Ross 	smb_credinit(&scred, cr);
23134bff34e3Sthurlow 
2314*ff1e230cSjilinxpd 	/* Lookup the "old" name */
2315*ff1e230cSjilinxpd 	error = smbfslookup(odvp, onm, &ovp, cr, 0, ct);
2316*ff1e230cSjilinxpd 	if (error == 0) {
2317*ff1e230cSjilinxpd 		/*
2318*ff1e230cSjilinxpd 		 * Do the real rename work
2319*ff1e230cSjilinxpd 		 */
2320*ff1e230cSjilinxpd 		error = smbfsrename(odvp, ovp, ndvp, nnm, &scred, flags);
2321*ff1e230cSjilinxpd 		VN_RELE(ovp);
23224bff34e3Sthurlow 	}
23234bff34e3Sthurlow 
2324*ff1e230cSjilinxpd 	smb_credrele(&scred);
2325*ff1e230cSjilinxpd 	smbfs_rw_exit(&odnp->r_rwlock);
2326*ff1e230cSjilinxpd 	smbfs_rw_exit(&ndnp->r_rwlock);
2327*ff1e230cSjilinxpd 
2328*ff1e230cSjilinxpd 	return (error);
2329*ff1e230cSjilinxpd }
2330*ff1e230cSjilinxpd 
2331*ff1e230cSjilinxpd /*
2332*ff1e230cSjilinxpd  * smbfsrename does the real work of renaming in SMBFS
2333*ff1e230cSjilinxpd  * Caller has done dir access checks etc.
2334*ff1e230cSjilinxpd  */
2335*ff1e230cSjilinxpd /* ARGSUSED */
2336*ff1e230cSjilinxpd static int
2337*ff1e230cSjilinxpd smbfsrename(vnode_t *odvp, vnode_t *ovp, vnode_t *ndvp, char *nnm,
2338*ff1e230cSjilinxpd     struct smb_cred *scred, int flags)
2339*ff1e230cSjilinxpd {
2340*ff1e230cSjilinxpd 	smbnode_t	*odnp = VTOSMB(odvp);
2341*ff1e230cSjilinxpd 	smbnode_t	*onp = VTOSMB(ovp);
2342*ff1e230cSjilinxpd 	smbnode_t	*ndnp = VTOSMB(ndvp);
2343*ff1e230cSjilinxpd 	vnode_t		*nvp = NULL;
2344*ff1e230cSjilinxpd 	int		error;
2345*ff1e230cSjilinxpd 	int		nvp_locked = 0;
2346*ff1e230cSjilinxpd 
2347*ff1e230cSjilinxpd 	/* Things our caller should have checked. */
2348*ff1e230cSjilinxpd 	ASSERT(curproc->p_zone == VTOSMI(odvp)->smi_zone_ref.zref_zone);
2349*ff1e230cSjilinxpd 	ASSERT(odvp->v_vfsp == ndvp->v_vfsp);
2350*ff1e230cSjilinxpd 	ASSERT(odnp->r_rwlock.owner == curthread);
2351*ff1e230cSjilinxpd 	ASSERT(ndnp->r_rwlock.owner == curthread);
23524bff34e3Sthurlow 
23534bff34e3Sthurlow 	/*
23544bff34e3Sthurlow 	 * Lookup the target file.  If it exists, it needs to be
23554bff34e3Sthurlow 	 * checked to see whether it is a mount point and whether
23564bff34e3Sthurlow 	 * it is active (open).
23574bff34e3Sthurlow 	 */
2358*ff1e230cSjilinxpd 	error = smbfslookup(ndvp, nnm, &nvp, scred->scr_cred, 0, NULL);
23594bff34e3Sthurlow 	if (!error) {
23604bff34e3Sthurlow 		/*
23614bff34e3Sthurlow 		 * Target (nvp) already exists.  Check that it
23624bff34e3Sthurlow 		 * has the same type as the source.  The server
23634bff34e3Sthurlow 		 * will check this also, (and more reliably) but
23644bff34e3Sthurlow 		 * this lets us return the correct error codes.
23654bff34e3Sthurlow 		 */
23664bff34e3Sthurlow 		if (ovp->v_type == VDIR) {
23674bff34e3Sthurlow 			if (nvp->v_type != VDIR) {
23684bff34e3Sthurlow 				error = ENOTDIR;
23694bff34e3Sthurlow 				goto out;
23704bff34e3Sthurlow 			}
23714bff34e3Sthurlow 		} else {
23724bff34e3Sthurlow 			if (nvp->v_type == VDIR) {
23734bff34e3Sthurlow 				error = EISDIR;
23744bff34e3Sthurlow 				goto out;
23754bff34e3Sthurlow 			}
23764bff34e3Sthurlow 		}
23774bff34e3Sthurlow 
23784bff34e3Sthurlow 		/*
23794bff34e3Sthurlow 		 * POSIX dictates that when the source and target
23804bff34e3Sthurlow 		 * entries refer to the same file object, rename
23814bff34e3Sthurlow 		 * must do nothing and exit without error.
23824bff34e3Sthurlow 		 */
23834bff34e3Sthurlow 		if (ovp == nvp) {
23844bff34e3Sthurlow 			error = 0;
23854bff34e3Sthurlow 			goto out;
23864bff34e3Sthurlow 		}
23874bff34e3Sthurlow 
23884bff34e3Sthurlow 		/*
23894bff34e3Sthurlow 		 * Also must ensure the target is not a mount point,
23904bff34e3Sthurlow 		 * and keep mount/umount away until we're done.
23914bff34e3Sthurlow 		 */
23924bff34e3Sthurlow 		if (vn_vfsrlock(nvp)) {
23934bff34e3Sthurlow 			error = EBUSY;
23944bff34e3Sthurlow 			goto out;
23954bff34e3Sthurlow 		}
23964bff34e3Sthurlow 		nvp_locked = 1;
23974bff34e3Sthurlow 		if (vn_mountedvfs(nvp) != NULL) {
23984bff34e3Sthurlow 			error = EBUSY;
23994bff34e3Sthurlow 			goto out;
24004bff34e3Sthurlow 		}
24014bff34e3Sthurlow 
240291d632c8Sgwr 		/*
2403*ff1e230cSjilinxpd 		 * CIFS may give a SHARING_VIOLATION error when
240491d632c8Sgwr 		 * trying to rename onto an exising object,
240591d632c8Sgwr 		 * so try to remove the target first.
240691d632c8Sgwr 		 * (Only for files, not directories.)
240791d632c8Sgwr 		 */
240891d632c8Sgwr 		if (nvp->v_type == VDIR) {
240991d632c8Sgwr 			error = EEXIST;
241091d632c8Sgwr 			goto out;
241191d632c8Sgwr 		}
2412*ff1e230cSjilinxpd 		error = smbfsremove(ndvp, nvp, scred, flags);
2413*ff1e230cSjilinxpd 		if (error != 0)
24144bff34e3Sthurlow 			goto out;
241502d09e03SGordon Ross 
241691d632c8Sgwr 		/*
241791d632c8Sgwr 		 * OK, removed the target file.  Continue as if
241891d632c8Sgwr 		 * lookup target had failed (nvp == NULL).
241991d632c8Sgwr 		 */
242091d632c8Sgwr 		vn_vfsunlock(nvp);
242191d632c8Sgwr 		nvp_locked = 0;
242291d632c8Sgwr 		VN_RELE(nvp);
242391d632c8Sgwr 		nvp = NULL;
24244bff34e3Sthurlow 	} /* nvp */
24254bff34e3Sthurlow 
242602d09e03SGordon Ross 	smbfs_attrcache_remove(onp);
242702d09e03SGordon Ross 
2428*ff1e230cSjilinxpd 	error = smbfs_smb_rename(onp, ndnp, nnm, strlen(nnm), scred);
24294bff34e3Sthurlow 
243002d09e03SGordon Ross 	/*
243102d09e03SGordon Ross 	 * If the old name should no longer exist,
243202d09e03SGordon Ross 	 * discard any cached attributes under it.
243302d09e03SGordon Ross 	 */
243402d09e03SGordon Ross 	if (error == 0)
243502d09e03SGordon Ross 		smbfs_attrcache_prune(onp);
24364bff34e3Sthurlow 
24374bff34e3Sthurlow out:
24384bff34e3Sthurlow 	if (nvp) {
24394bff34e3Sthurlow 		if (nvp_locked)
24404bff34e3Sthurlow 			vn_vfsunlock(nvp);
24414bff34e3Sthurlow 		VN_RELE(nvp);
24424bff34e3Sthurlow 	}
24434bff34e3Sthurlow 
24444bff34e3Sthurlow 	return (error);
24454bff34e3Sthurlow }
24464bff34e3Sthurlow 
24474bff34e3Sthurlow /*
24484bff34e3Sthurlow  * XXX
24494bff34e3Sthurlow  * vsecattr_t is new to build 77, and we need to eventually support
24504bff34e3Sthurlow  * it in order to create an ACL when an object is created.
24514bff34e3Sthurlow  *
24524bff34e3Sthurlow  * This op should support the new FIGNORECASE flag for case-insensitive
24534bff34e3Sthurlow  * lookups, per PSARC 2007/244.
24544bff34e3Sthurlow  */
24554bff34e3Sthurlow /* ARGSUSED */
24564bff34e3Sthurlow static int
24574bff34e3Sthurlow smbfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp,
24584bff34e3Sthurlow 	cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp)
24594bff34e3Sthurlow {
24604bff34e3Sthurlow 	vnode_t		*vp;
24614bff34e3Sthurlow 	struct smbnode	*dnp = VTOSMB(dvp);
24624bff34e3Sthurlow 	struct smbmntinfo *smi = VTOSMI(dvp);
24634bff34e3Sthurlow 	struct smb_cred	scred;
24644bff34e3Sthurlow 	struct smbfattr	fattr;
24654bff34e3Sthurlow 	const char		*name = (const char *) nm;
24664bff34e3Sthurlow 	int		nmlen = strlen(name);
24674bff34e3Sthurlow 	int		error, hiderr;
24684bff34e3Sthurlow 
2469a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
24704bff34e3Sthurlow 		return (EPERM);
24714bff34e3Sthurlow 
24724bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
24734bff34e3Sthurlow 		return (EIO);
24744bff34e3Sthurlow 
24754bff34e3Sthurlow 	if ((nmlen == 1 && name[0] == '.') ||
24764bff34e3Sthurlow 	    (nmlen == 2 && name[0] == '.' && name[1] == '.'))
24774bff34e3Sthurlow 		return (EEXIST);
24784bff34e3Sthurlow 
247991d632c8Sgwr 	/* Only plain files are allowed in V_XATTRDIR. */
248091d632c8Sgwr 	if (dvp->v_flag & V_XATTRDIR)
248191d632c8Sgwr 		return (EINVAL);
248291d632c8Sgwr 
24834bff34e3Sthurlow 	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
24844bff34e3Sthurlow 		return (EINTR);
2485613a2f6bSGordon Ross 	smb_credinit(&scred, cr);
24864bff34e3Sthurlow 
24874bff34e3Sthurlow 	/*
24884bff34e3Sthurlow 	 * XXX: Do we need r_lkserlock too?
24894bff34e3Sthurlow 	 * No use of any shared fid or fctx...
24904bff34e3Sthurlow 	 */
24914bff34e3Sthurlow 
24924bff34e3Sthurlow 	/*
24934bff34e3Sthurlow 	 * Require write access in the containing directory.
24944bff34e3Sthurlow 	 */
24954bff34e3Sthurlow 	error = smbfs_access(dvp, VWRITE, 0, cr, ct);
24964bff34e3Sthurlow 	if (error)
24974bff34e3Sthurlow 		goto out;
24984bff34e3Sthurlow 
24994bff34e3Sthurlow 	error = smbfs_smb_mkdir(dnp, name, nmlen, &scred);
25004bff34e3Sthurlow 	if (error)
25014bff34e3Sthurlow 		goto out;
25024bff34e3Sthurlow 
25034bff34e3Sthurlow 	error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred);
25044bff34e3Sthurlow 	if (error)
25054bff34e3Sthurlow 		goto out;
25064bff34e3Sthurlow 
25074bff34e3Sthurlow 	smbfs_attr_touchdir(dnp);
25084bff34e3Sthurlow 
25094bff34e3Sthurlow 	error = smbfs_nget(dvp, name, nmlen, &fattr, &vp);
25104bff34e3Sthurlow 	if (error)
25114bff34e3Sthurlow 		goto out;
25124bff34e3Sthurlow 
25134bff34e3Sthurlow 	if (name[0] == '.')
25144bff34e3Sthurlow 		if ((hiderr = smbfs_smb_hideit(VTOSMB(vp), NULL, 0, &scred)))
25154bff34e3Sthurlow 			SMBVDEBUG("hide failure %d\n", hiderr);
25164bff34e3Sthurlow 
25174bff34e3Sthurlow 	/* Success! */
25184bff34e3Sthurlow 	*vpp = vp;
25194bff34e3Sthurlow 	error = 0;
25204bff34e3Sthurlow out:
25214bff34e3Sthurlow 	smb_credrele(&scred);
25224bff34e3Sthurlow 	smbfs_rw_exit(&dnp->r_rwlock);
25234bff34e3Sthurlow 
25244bff34e3Sthurlow 	if (name != nm)
25254bff34e3Sthurlow 		smbfs_name_free(name, nmlen);
25264bff34e3Sthurlow 
25274bff34e3Sthurlow 	return (error);
25284bff34e3Sthurlow }
25294bff34e3Sthurlow 
25304bff34e3Sthurlow /*
25314bff34e3Sthurlow  * XXX
25324bff34e3Sthurlow  * This op should support the new FIGNORECASE flag for case-insensitive
25334bff34e3Sthurlow  * lookups, per PSARC 2007/244.
25344bff34e3Sthurlow  */
25354bff34e3Sthurlow /* ARGSUSED */
25364bff34e3Sthurlow static int
25374bff34e3Sthurlow smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
25384bff34e3Sthurlow 	caller_context_t *ct, int flags)
25394bff34e3Sthurlow {
25404bff34e3Sthurlow 	vnode_t		*vp = NULL;
25414bff34e3Sthurlow 	int		vp_locked = 0;
25424bff34e3Sthurlow 	struct smbmntinfo *smi = VTOSMI(dvp);
25434bff34e3Sthurlow 	struct smbnode	*dnp = VTOSMB(dvp);
25444bff34e3Sthurlow 	struct smbnode	*np;
25454bff34e3Sthurlow 	struct smb_cred	scred;
25464bff34e3Sthurlow 	int		error;
25474bff34e3Sthurlow 
2548a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
25494bff34e3Sthurlow 		return (EPERM);
25504bff34e3Sthurlow 
25514bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
25524bff34e3Sthurlow 		return (EIO);
25534bff34e3Sthurlow 
25544bff34e3Sthurlow 	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
25554bff34e3Sthurlow 		return (EINTR);
2556613a2f6bSGordon Ross 	smb_credinit(&scred, cr);
25574bff34e3Sthurlow 
25584bff34e3Sthurlow 	/*
25594bff34e3Sthurlow 	 * Require w/x access in the containing directory.
25604bff34e3Sthurlow 	 * Server handles all other access checks.
25614bff34e3Sthurlow 	 */
25624bff34e3Sthurlow 	error = smbfs_access(dvp, VEXEC|VWRITE, 0, cr, ct);
25634bff34e3Sthurlow 	if (error)
25644bff34e3Sthurlow 		goto out;
25654bff34e3Sthurlow 
25664bff34e3Sthurlow 	/*
25674bff34e3Sthurlow 	 * First lookup the entry to be removed.
25684bff34e3Sthurlow 	 */
25694bff34e3Sthurlow 	error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
25704bff34e3Sthurlow 	if (error)
25714bff34e3Sthurlow 		goto out;
25724bff34e3Sthurlow 	np = VTOSMB(vp);
25734bff34e3Sthurlow 
25744bff34e3Sthurlow 	/*
25754bff34e3Sthurlow 	 * Disallow rmdir of "." or current dir, or the FS root.
25764bff34e3Sthurlow 	 * Also make sure it's a directory, not a mount point,
25774bff34e3Sthurlow 	 * and lock to keep mount/umount away until we're done.
25784bff34e3Sthurlow 	 */
25794bff34e3Sthurlow 	if ((vp == dvp) || (vp == cdir) || (vp->v_flag & VROOT)) {
25804bff34e3Sthurlow 		error = EINVAL;
25814bff34e3Sthurlow 		goto out;
25824bff34e3Sthurlow 	}
25834bff34e3Sthurlow 	if (vp->v_type != VDIR) {
25844bff34e3Sthurlow 		error = ENOTDIR;
25854bff34e3Sthurlow 		goto out;
25864bff34e3Sthurlow 	}
25874bff34e3Sthurlow 	if (vn_vfsrlock(vp)) {
25884bff34e3Sthurlow 		error = EBUSY;
25894bff34e3Sthurlow 		goto out;
25904bff34e3Sthurlow 	}
25914bff34e3Sthurlow 	vp_locked = 1;
25924bff34e3Sthurlow 	if (vn_mountedvfs(vp) != NULL) {
25934bff34e3Sthurlow 		error = EBUSY;
25944bff34e3Sthurlow 		goto out;
25954bff34e3Sthurlow 	}
25964bff34e3Sthurlow 
259702d09e03SGordon Ross 	smbfs_attrcache_remove(np);
259802d09e03SGordon Ross 	error = smbfs_smb_rmdir(np, &scred);
259991d632c8Sgwr 
260091d632c8Sgwr 	/*
260102d09e03SGordon Ross 	 * Similar to smbfs_remove
260291d632c8Sgwr 	 */
260302d09e03SGordon Ross 	switch (error) {
260402d09e03SGordon Ross 	case 0:
260502d09e03SGordon Ross 	case ENOENT:
260602d09e03SGordon Ross 	case ENOTDIR:
260702d09e03SGordon Ross 		smbfs_attrcache_prune(np);
260802d09e03SGordon Ross 		break;
260991d632c8Sgwr 	}
261091d632c8Sgwr 
26114bff34e3Sthurlow 	if (error)
26124bff34e3Sthurlow 		goto out;
26134bff34e3Sthurlow 
26144bff34e3Sthurlow 	mutex_enter(&np->r_statelock);
26154bff34e3Sthurlow 	dnp->n_flag |= NMODIFIED;
26164bff34e3Sthurlow 	mutex_exit(&np->r_statelock);
26174bff34e3Sthurlow 	smbfs_attr_touchdir(dnp);
261802d09e03SGordon Ross 	smbfs_rmhash(np);
26194bff34e3Sthurlow 
26204bff34e3Sthurlow out:
26214bff34e3Sthurlow 	if (vp) {
26224bff34e3Sthurlow 		if (vp_locked)
26234bff34e3Sthurlow 			vn_vfsunlock(vp);
26244bff34e3Sthurlow 		VN_RELE(vp);
26254bff34e3Sthurlow 	}
26264bff34e3Sthurlow 	smb_credrele(&scred);
26274bff34e3Sthurlow 	smbfs_rw_exit(&dnp->r_rwlock);
26284bff34e3Sthurlow 
26294bff34e3Sthurlow 	return (error);
26304bff34e3Sthurlow }
26314bff34e3Sthurlow 
26324bff34e3Sthurlow 
26334bff34e3Sthurlow /* ARGSUSED */
26344bff34e3Sthurlow static int
26354bff34e3Sthurlow smbfs_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp,
26364bff34e3Sthurlow 	caller_context_t *ct, int flags)
26374bff34e3Sthurlow {
26384bff34e3Sthurlow 	struct smbnode	*np = VTOSMB(vp);
26394bff34e3Sthurlow 	int		error = 0;
26404bff34e3Sthurlow 	smbmntinfo_t	*smi;
26414bff34e3Sthurlow 
26424bff34e3Sthurlow 	smi = VTOSMI(vp);
26434bff34e3Sthurlow 
2644a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
26454bff34e3Sthurlow 		return (EIO);
26464bff34e3Sthurlow 
26474bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
26484bff34e3Sthurlow 		return (EIO);
26494bff34e3Sthurlow 
26504bff34e3Sthurlow 	/*
26514bff34e3Sthurlow 	 * Require read access in the directory.
26524bff34e3Sthurlow 	 */
26534bff34e3Sthurlow 	error = smbfs_access(vp, VREAD, 0, cr, ct);
26544bff34e3Sthurlow 	if (error)
26554bff34e3Sthurlow 		return (error);
26564bff34e3Sthurlow 
26574bff34e3Sthurlow 	ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER));
26584bff34e3Sthurlow 
26594bff34e3Sthurlow 	/*
26604bff34e3Sthurlow 	 * XXX: Todo readdir cache here
26614bff34e3Sthurlow 	 * Note: NFS code is just below this.
26624bff34e3Sthurlow 	 *
26634bff34e3Sthurlow 	 * I am serializing the entire readdir opreation
26644bff34e3Sthurlow 	 * now since we have not yet implemented readdir
26654bff34e3Sthurlow 	 * cache. This fix needs to be revisited once
26664bff34e3Sthurlow 	 * we implement readdir cache.
26674bff34e3Sthurlow 	 */
26684bff34e3Sthurlow 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp)))
26694bff34e3Sthurlow 		return (EINTR);
26704bff34e3Sthurlow 
26714bff34e3Sthurlow 	error = smbfs_readvdir(vp, uiop, cr, eofp, ct);
26724bff34e3Sthurlow 
26734bff34e3Sthurlow 	smbfs_rw_exit(&np->r_lkserlock);
26744bff34e3Sthurlow 
26754bff34e3Sthurlow 	return (error);
26764bff34e3Sthurlow }
26774bff34e3Sthurlow 
26784bff34e3Sthurlow /* ARGSUSED */
26794bff34e3Sthurlow static int
26804bff34e3Sthurlow smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
26814bff34e3Sthurlow 	caller_context_t *ct)
26824bff34e3Sthurlow {
26835ecede33SGordon Ross 	/*
26845ecede33SGordon Ross 	 * Note: "limit" tells the SMB-level FindFirst/FindNext
26855ecede33SGordon Ross 	 * functions how many directory entries to request in
26865ecede33SGordon Ross 	 * each OtW call.  It needs to be large enough so that
26875ecede33SGordon Ross 	 * we don't make lots of tiny OtW requests, but there's
26885ecede33SGordon Ross 	 * no point making it larger than the maximum number of
26895ecede33SGordon Ross 	 * OtW entries that would fit in a maximum sized trans2
26905ecede33SGordon Ross 	 * response (64k / 48).  Beyond that, it's just tuning.
26915ecede33SGordon Ross 	 * WinNT used 512, Win2k used 1366.  We use 1000.
26925ecede33SGordon Ross 	 */
26935ecede33SGordon Ross 	static const int limit = 1000;
26945ecede33SGordon Ross 	/* Largest possible dirent size. */
26955ecede33SGordon Ross 	static const size_t dbufsiz = DIRENT64_RECLEN(SMB_MAXFNAMELEN);
26964bff34e3Sthurlow 	struct smb_cred scred;
26974bff34e3Sthurlow 	vnode_t		*newvp;
26984bff34e3Sthurlow 	struct smbnode	*np = VTOSMB(vp);
26994bff34e3Sthurlow 	struct smbfs_fctx *ctx;
27005ecede33SGordon Ross 	struct dirent64 *dp;
27015ecede33SGordon Ross 	ssize_t		save_resid;
27025ecede33SGordon Ross 	offset_t	save_offset; /* 64 bits */
27035ecede33SGordon Ross 	int		offset; /* yes, 32 bits */
27045ecede33SGordon Ross 	int		nmlen, error;
27055ecede33SGordon Ross 	ushort_t	reclen;
27064bff34e3Sthurlow 
2707a19609f8Sjv 	ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone_ref.zref_zone);
27084bff34e3Sthurlow 
27094bff34e3Sthurlow 	/* Make sure we serialize for n_dirseq use. */
27104bff34e3Sthurlow 	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_WRITER));
27114bff34e3Sthurlow 
27125ecede33SGordon Ross 	/*
27135ecede33SGordon Ross 	 * Make sure smbfs_open filled in n_dirseq
27145ecede33SGordon Ross 	 */
27155ecede33SGordon Ross 	if (np->n_dirseq == NULL)
27165ecede33SGordon Ross 		return (EBADF);
27175ecede33SGordon Ross 
27185ecede33SGordon Ross 	/* Check for overflow of (32-bit) directory offset. */
27195ecede33SGordon Ross 	if (uio->uio_loffset < 0 || uio->uio_loffset > INT32_MAX ||
27205ecede33SGordon Ross 	    (uio->uio_loffset + uio->uio_resid) > INT32_MAX)
27215ecede33SGordon Ross 		return (EINVAL);
27225ecede33SGordon Ross 
27235ecede33SGordon Ross 	/* Require space for at least one dirent. */
27245ecede33SGordon Ross 	if (uio->uio_resid < dbufsiz)
27254bff34e3Sthurlow 		return (EINVAL);
27264bff34e3Sthurlow 
27274bff34e3Sthurlow 	SMBVDEBUG("dirname='%s'\n", np->n_rpath);
2728613a2f6bSGordon Ross 	smb_credinit(&scred, cr);
27294bff34e3Sthurlow 	dp = kmem_alloc(dbufsiz, KM_SLEEP);
27304bff34e3Sthurlow 
27315ecede33SGordon Ross 	save_resid = uio->uio_resid;
27325ecede33SGordon Ross 	save_offset = uio->uio_loffset;
27335ecede33SGordon Ross 	offset = uio->uio_offset;
27345ecede33SGordon Ross 	SMBVDEBUG("in: offset=%d, resid=%d\n",
27355ecede33SGordon Ross 	    (int)uio->uio_offset, (int)uio->uio_resid);
27365ecede33SGordon Ross 	error = 0;
27374bff34e3Sthurlow 
27384bff34e3Sthurlow 	/*
27394bff34e3Sthurlow 	 * Generate the "." and ".." entries here so we can
27404bff34e3Sthurlow 	 * (1) make sure they appear (but only once), and
27414bff34e3Sthurlow 	 * (2) deal with getting their I numbers which the
27424bff34e3Sthurlow 	 * findnext below does only for normal names.
27434bff34e3Sthurlow 	 */
27445ecede33SGordon Ross 	while (offset < FIRST_DIROFS) {
27455ecede33SGordon Ross 		/*
27465ecede33SGordon Ross 		 * Tricky bit filling in the first two:
27475ecede33SGordon Ross 		 * offset 0 is ".", offset 1 is ".."
27485ecede33SGordon Ross 		 * so strlen of these is offset+1.
27495ecede33SGordon Ross 		 */
27504bff34e3Sthurlow 		reclen = DIRENT64_RECLEN(offset + 1);
27515ecede33SGordon Ross 		if (uio->uio_resid < reclen)
27525ecede33SGordon Ross 			goto out;
27534bff34e3Sthurlow 		bzero(dp, reclen);
27544bff34e3Sthurlow 		dp->d_reclen = reclen;
27554bff34e3Sthurlow 		dp->d_name[0] = '.';
27564bff34e3Sthurlow 		dp->d_name[1] = '.';
27574bff34e3Sthurlow 		dp->d_name[offset + 1] = '\0';
27584bff34e3Sthurlow 		/*
27594bff34e3Sthurlow 		 * Want the real I-numbers for the "." and ".."
27604bff34e3Sthurlow 		 * entries.  For these two names, we know that
27615ecede33SGordon Ross 		 * smbfslookup can get the nodes efficiently.
27624bff34e3Sthurlow 		 */
27634bff34e3Sthurlow 		error = smbfslookup(vp, dp->d_name, &newvp, cr, 1, ct);
27644bff34e3Sthurlow 		if (error) {
27654bff34e3Sthurlow 			dp->d_ino = np->n_ino + offset; /* fiction */
27664bff34e3Sthurlow 		} else {
27674bff34e3Sthurlow 			dp->d_ino = VTOSMB(newvp)->n_ino;
27684bff34e3Sthurlow 			VN_RELE(newvp);
27694bff34e3Sthurlow 		}
27705ecede33SGordon Ross 		/*
27715ecede33SGordon Ross 		 * Note: d_off is the offset that a user-level program
27725ecede33SGordon Ross 		 * should seek to for reading the NEXT directory entry.
27735ecede33SGordon Ross 		 * See libc: readdir, telldir, seekdir
27745ecede33SGordon Ross 		 */
27755ecede33SGordon Ross 		dp->d_off = offset + 1;
27765ecede33SGordon Ross 		error = uiomove(dp, reclen, UIO_READ, uio);
27774bff34e3Sthurlow 		if (error)
27784bff34e3Sthurlow 			goto out;
27795ecede33SGordon Ross 		/*
27805ecede33SGordon Ross 		 * Note: uiomove updates uio->uio_offset,
27815ecede33SGordon Ross 		 * but we want it to be our "cookie" value,
27825ecede33SGordon Ross 		 * which just counts dirents ignoring size.
27835ecede33SGordon Ross 		 */
27844bff34e3Sthurlow 		uio->uio_offset = ++offset;
27854bff34e3Sthurlow 	}
27865ecede33SGordon Ross 
27875ecede33SGordon Ross 	/*
27885ecede33SGordon Ross 	 * If there was a backward seek, we have to reopen.
27895ecede33SGordon Ross 	 */
27905ecede33SGordon Ross 	if (offset < np->n_dirofs) {
27915ecede33SGordon Ross 		SMBVDEBUG("Reopening search %d:%d\n",
27925ecede33SGordon Ross 		    offset, np->n_dirofs);
27934bff34e3Sthurlow 		error = smbfs_smb_findopen(np, "*", 1,
27944bff34e3Sthurlow 		    SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR,
27954bff34e3Sthurlow 		    &scred, &ctx);
27964bff34e3Sthurlow 		if (error) {
27974bff34e3Sthurlow 			SMBVDEBUG("can not open search, error = %d", error);
27984bff34e3Sthurlow 			goto out;
27994bff34e3Sthurlow 		}
28005ecede33SGordon Ross 		/* free the old one */
28015ecede33SGordon Ross 		(void) smbfs_smb_findclose(np->n_dirseq, &scred);
28025ecede33SGordon Ross 		/* save the new one */
28034bff34e3Sthurlow 		np->n_dirseq = ctx;
28045ecede33SGordon Ross 		np->n_dirofs = FIRST_DIROFS;
28055ecede33SGordon Ross 	} else {
28064bff34e3Sthurlow 		ctx = np->n_dirseq;
28075ecede33SGordon Ross 	}
28085ecede33SGordon Ross 
28095ecede33SGordon Ross 	/*
28105ecede33SGordon Ross 	 * Skip entries before the requested offset.
28115ecede33SGordon Ross 	 */
28124bff34e3Sthurlow 	while (np->n_dirofs < offset) {
28135ecede33SGordon Ross 		error = smbfs_smb_findnext(ctx, limit, &scred);
28145ecede33SGordon Ross 		if (error != 0)
28154bff34e3Sthurlow 			goto out;
28165ecede33SGordon Ross 		np->n_dirofs++;
28174bff34e3Sthurlow 	}
28185ecede33SGordon Ross 
28195ecede33SGordon Ross 	/*
28205ecede33SGordon Ross 	 * While there's room in the caller's buffer:
28215ecede33SGordon Ross 	 *	get a directory entry from SMB,
28225ecede33SGordon Ross 	 *	convert to a dirent, copyout.
28235ecede33SGordon Ross 	 * We stop when there is no longer room for a
28245ecede33SGordon Ross 	 * maximum sized dirent because we must decide
28255ecede33SGordon Ross 	 * before we know anything about the next entry.
28265ecede33SGordon Ross 	 */
28275ecede33SGordon Ross 	while (uio->uio_resid >= dbufsiz) {
28284bff34e3Sthurlow 		error = smbfs_smb_findnext(ctx, limit, &scred);
28295ecede33SGordon Ross 		if (error != 0)
28305ecede33SGordon Ross 			goto out;
28314bff34e3Sthurlow 		np->n_dirofs++;
28325ecede33SGordon Ross 
28334bff34e3Sthurlow 		/* Sanity check the name length. */
28344bff34e3Sthurlow 		nmlen = ctx->f_nmlen;
2835613a2f6bSGordon Ross 		if (nmlen > SMB_MAXFNAMELEN) {
2836613a2f6bSGordon Ross 			nmlen = SMB_MAXFNAMELEN;
28374bff34e3Sthurlow 			SMBVDEBUG("Truncating name: %s\n", ctx->f_name);
28384bff34e3Sthurlow 		}
28394bff34e3Sthurlow 		if (smbfs_fastlookup) {
284002d09e03SGordon Ross 			/* See comment at smbfs_fastlookup above. */
28415ecede33SGordon Ross 			if (smbfs_nget(vp, ctx->f_name, nmlen,
28425ecede33SGordon Ross 			    &ctx->f_attr, &newvp) == 0)
28434bff34e3Sthurlow 				VN_RELE(newvp);
28444bff34e3Sthurlow 		}
28455ecede33SGordon Ross 
28465ecede33SGordon Ross 		reclen = DIRENT64_RECLEN(nmlen);
28475ecede33SGordon Ross 		bzero(dp, reclen);
28485ecede33SGordon Ross 		dp->d_reclen = reclen;
28495ecede33SGordon Ross 		bcopy(ctx->f_name, dp->d_name, nmlen);
28505ecede33SGordon Ross 		dp->d_name[nmlen] = '\0';
285102d09e03SGordon Ross 		dp->d_ino = ctx->f_inum;
28525ecede33SGordon Ross 		dp->d_off = offset + 1;	/* See d_off comment above */
28535ecede33SGordon Ross 		error = uiomove(dp, reclen, UIO_READ, uio);
28544bff34e3Sthurlow 		if (error)
28555ecede33SGordon Ross 			goto out;
28565ecede33SGordon Ross 		/* See comment re. uio_offset above. */
28574bff34e3Sthurlow 		uio->uio_offset = ++offset;
28584bff34e3Sthurlow 	}
28595ecede33SGordon Ross 
28604bff34e3Sthurlow out:
28615ecede33SGordon Ross 	/*
28625ecede33SGordon Ross 	 * When we come to the end of a directory, the
28635ecede33SGordon Ross 	 * SMB-level functions return ENOENT, but the
28645ecede33SGordon Ross 	 * caller is not expecting an error return.
28655ecede33SGordon Ross 	 *
28665ecede33SGordon Ross 	 * Also note that we must delay the call to
28675ecede33SGordon Ross 	 * smbfs_smb_findclose(np->n_dirseq, ...)
28685ecede33SGordon Ross 	 * until smbfs_close so that all reads at the
28695ecede33SGordon Ross 	 * end of the directory will return no data.
28705ecede33SGordon Ross 	 */
28715ecede33SGordon Ross 	if (error == ENOENT) {
28725ecede33SGordon Ross 		error = 0;
28735ecede33SGordon Ross 		if (eofp)
28745ecede33SGordon Ross 			*eofp = 1;
28755ecede33SGordon Ross 	}
28765ecede33SGordon Ross 	/*
28775ecede33SGordon Ross 	 * If we encountered an error (i.e. "access denied")
28785ecede33SGordon Ross 	 * from the FindFirst call, we will have copied out
28795ecede33SGordon Ross 	 * the "." and ".." entries leaving offset == 2.
28805ecede33SGordon Ross 	 * In that case, restore the original offset/resid
28815ecede33SGordon Ross 	 * so the caller gets no data with the error.
28825ecede33SGordon Ross 	 */
28835ecede33SGordon Ross 	if (error != 0 && offset == FIRST_DIROFS) {
28845ecede33SGordon Ross 		uio->uio_loffset = save_offset;
28855ecede33SGordon Ross 		uio->uio_resid = save_resid;
28865ecede33SGordon Ross 	}
28875ecede33SGordon Ross 	SMBVDEBUG("out: offset=%d, resid=%d\n",
28885ecede33SGordon Ross 	    (int)uio->uio_offset, (int)uio->uio_resid);
28895ecede33SGordon Ross 
28904bff34e3Sthurlow 	kmem_free(dp, dbufsiz);
28914bff34e3Sthurlow 	smb_credrele(&scred);
28924bff34e3Sthurlow 	return (error);
28934bff34e3Sthurlow }
28944bff34e3Sthurlow 
28954bff34e3Sthurlow 
28964bff34e3Sthurlow /*
28974bff34e3Sthurlow  * The pair of functions VOP_RWLOCK, VOP_RWUNLOCK
28984bff34e3Sthurlow  * are optional functions that are called by:
28994bff34e3Sthurlow  *    getdents, before/after VOP_READDIR
29004bff34e3Sthurlow  *    pread, before/after ... VOP_READ
29014bff34e3Sthurlow  *    pwrite, before/after ... VOP_WRITE
29024bff34e3Sthurlow  *    (other places)
29034bff34e3Sthurlow  *
29044bff34e3Sthurlow  * Careful here: None of the above check for any
29054bff34e3Sthurlow  * error returns from VOP_RWLOCK / VOP_RWUNLOCK!
29064bff34e3Sthurlow  * In fact, the return value from _rwlock is NOT
29074bff34e3Sthurlow  * an error code, but V_WRITELOCK_TRUE / _FALSE.
29084bff34e3Sthurlow  *
29094bff34e3Sthurlow  * Therefore, it's up to _this_ code to make sure
29104bff34e3Sthurlow  * the lock state remains balanced, which means
29114bff34e3Sthurlow  * we can't "bail out" on interrupts, etc.
29124bff34e3Sthurlow  */
29134bff34e3Sthurlow 
29144bff34e3Sthurlow /* ARGSUSED2 */
29154bff34e3Sthurlow static int
29164bff34e3Sthurlow smbfs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
29174bff34e3Sthurlow {
29184bff34e3Sthurlow 	smbnode_t	*np = VTOSMB(vp);
29194bff34e3Sthurlow 
29204bff34e3Sthurlow 	if (!write_lock) {
29214bff34e3Sthurlow 		(void) smbfs_rw_enter_sig(&np->r_rwlock, RW_READER, FALSE);
29224bff34e3Sthurlow 		return (V_WRITELOCK_FALSE);
29234bff34e3Sthurlow 	}
29244bff34e3Sthurlow 
29254bff34e3Sthurlow 
29264bff34e3Sthurlow 	(void) smbfs_rw_enter_sig(&np->r_rwlock, RW_WRITER, FALSE);
29274bff34e3Sthurlow 	return (V_WRITELOCK_TRUE);
29284bff34e3Sthurlow }
29294bff34e3Sthurlow 
29304bff34e3Sthurlow /* ARGSUSED */
29314bff34e3Sthurlow static void
29324bff34e3Sthurlow smbfs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
29334bff34e3Sthurlow {
29344bff34e3Sthurlow 	smbnode_t	*np = VTOSMB(vp);
29354bff34e3Sthurlow 
29364bff34e3Sthurlow 	smbfs_rw_exit(&np->r_rwlock);
29374bff34e3Sthurlow }
29384bff34e3Sthurlow 
29394bff34e3Sthurlow 
29404bff34e3Sthurlow /* ARGSUSED */
29414bff34e3Sthurlow static int
29424bff34e3Sthurlow smbfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
29434bff34e3Sthurlow {
29444bff34e3Sthurlow 	smbmntinfo_t	*smi;
29454bff34e3Sthurlow 
29464bff34e3Sthurlow 	smi = VTOSMI(vp);
29474bff34e3Sthurlow 
2948a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
29494bff34e3Sthurlow 		return (EPERM);
29504bff34e3Sthurlow 
29514bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
29524bff34e3Sthurlow 		return (EIO);
29534bff34e3Sthurlow 
29544bff34e3Sthurlow 	/*
29554bff34e3Sthurlow 	 * Because we stuff the readdir cookie into the offset field
29564bff34e3Sthurlow 	 * someone may attempt to do an lseek with the cookie which
29574bff34e3Sthurlow 	 * we want to succeed.
29584bff34e3Sthurlow 	 */
29594bff34e3Sthurlow 	if (vp->v_type == VDIR)
29604bff34e3Sthurlow 		return (0);
29614bff34e3Sthurlow 
29624bff34e3Sthurlow 	/* Like NFS3, just check for 63-bit overflow. */
29634bff34e3Sthurlow 	if (*noffp < 0)
29644bff34e3Sthurlow 		return (EINVAL);
29654bff34e3Sthurlow 
29664bff34e3Sthurlow 	return (0);
29674bff34e3Sthurlow }
29684bff34e3Sthurlow 
29694bff34e3Sthurlow 
29704bff34e3Sthurlow /*
29714bff34e3Sthurlow  * XXX
29724bff34e3Sthurlow  * This op may need to support PSARC 2007/440, nbmand changes for CIFS Service.
29734bff34e3Sthurlow  */
29744bff34e3Sthurlow static int
29754bff34e3Sthurlow smbfs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
29764bff34e3Sthurlow 	offset_t offset, struct flk_callback *flk_cbp, cred_t *cr,
29774bff34e3Sthurlow 	caller_context_t *ct)
29784bff34e3Sthurlow {
2979a19609f8Sjv 	if (curproc->p_zone != VTOSMI(vp)->smi_zone_ref.zref_zone)
29804bff34e3Sthurlow 		return (EIO);
29814bff34e3Sthurlow 
29824bff34e3Sthurlow 	if (VTOSMI(vp)->smi_flags & SMI_LLOCK)
29834bff34e3Sthurlow 		return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
29844bff34e3Sthurlow 	else
29854bff34e3Sthurlow 		return (ENOSYS);
29864bff34e3Sthurlow }
29874bff34e3Sthurlow 
29884bff34e3Sthurlow /*
29894bff34e3Sthurlow  * Free storage space associated with the specified vnode.  The portion
29904bff34e3Sthurlow  * to be freed is specified by bfp->l_start and bfp->l_len (already
29914bff34e3Sthurlow  * normalized to a "whence" of 0).
29924bff34e3Sthurlow  *
29934bff34e3Sthurlow  * Called by fcntl(fd, F_FREESP, lkp) for libc:ftruncate, etc.
29944bff34e3Sthurlow  */
29954bff34e3Sthurlow /* ARGSUSED */
29964bff34e3Sthurlow static int
29974bff34e3Sthurlow smbfs_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
29984bff34e3Sthurlow 	offset_t offset, cred_t *cr, caller_context_t *ct)
29994bff34e3Sthurlow {
30004bff34e3Sthurlow 	int		error;
30014bff34e3Sthurlow 	smbmntinfo_t	*smi;
30024bff34e3Sthurlow 
30034bff34e3Sthurlow 	smi = VTOSMI(vp);
30044bff34e3Sthurlow 
3005a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
30064bff34e3Sthurlow 		return (EIO);
30074bff34e3Sthurlow 
30084bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
30094bff34e3Sthurlow 		return (EIO);
30104bff34e3Sthurlow 
301191d632c8Sgwr 	/* Caller (fcntl) has checked v_type */
30124bff34e3Sthurlow 	ASSERT(vp->v_type == VREG);
30134bff34e3Sthurlow 	if (cmd != F_FREESP)
30144bff34e3Sthurlow 		return (EINVAL);
30154bff34e3Sthurlow 
30164bff34e3Sthurlow 	/*
30174bff34e3Sthurlow 	 * Like NFS3, no 32-bit offset checks here.
30184bff34e3Sthurlow 	 * Our SMB layer takes care to return EFBIG
30194bff34e3Sthurlow 	 * when it has to fallback to a 32-bit call.
30204bff34e3Sthurlow 	 */
30214bff34e3Sthurlow 
30224bff34e3Sthurlow 	error = convoff(vp, bfp, 0, offset);
30234bff34e3Sthurlow 	if (!error) {
30244bff34e3Sthurlow 		ASSERT(bfp->l_start >= 0);
30254bff34e3Sthurlow 		if (bfp->l_len == 0) {
30264bff34e3Sthurlow 			struct vattr va;
30274bff34e3Sthurlow 
30284bff34e3Sthurlow 			/*
30294bff34e3Sthurlow 			 * ftruncate should not change the ctime and
30304bff34e3Sthurlow 			 * mtime if we truncate the file to its
30314bff34e3Sthurlow 			 * previous size.
30324bff34e3Sthurlow 			 */
30334bff34e3Sthurlow 			va.va_mask = AT_SIZE;
30344bff34e3Sthurlow 			error = smbfsgetattr(vp, &va, cr);
30354bff34e3Sthurlow 			if (error || va.va_size == bfp->l_start)
30364bff34e3Sthurlow 				return (error);
30374bff34e3Sthurlow 			va.va_mask = AT_SIZE;
30384bff34e3Sthurlow 			va.va_size = bfp->l_start;
30394bff34e3Sthurlow 			error = smbfssetattr(vp, &va, 0, cr);
30404bff34e3Sthurlow 		} else
30414bff34e3Sthurlow 			error = EINVAL;
30424bff34e3Sthurlow 	}
30434bff34e3Sthurlow 
30444bff34e3Sthurlow 	return (error);
30454bff34e3Sthurlow }
30464bff34e3Sthurlow 
30474bff34e3Sthurlow /* ARGSUSED */
30484bff34e3Sthurlow static int
30494bff34e3Sthurlow smbfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
30504bff34e3Sthurlow 	caller_context_t *ct)
30514bff34e3Sthurlow {
305291d632c8Sgwr 	vfs_t *vfs;
30534bff34e3Sthurlow 	smbmntinfo_t *smi;
30544bff34e3Sthurlow 	struct smb_share *ssp;
30554bff34e3Sthurlow 
305691d632c8Sgwr 	vfs = vp->v_vfsp;
305791d632c8Sgwr 	smi = VFTOSMI(vfs);
30584bff34e3Sthurlow 
3059a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
30604bff34e3Sthurlow 		return (EIO);
30614bff34e3Sthurlow 
30624bff34e3Sthurlow 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
30634bff34e3Sthurlow 		return (EIO);
30644bff34e3Sthurlow 
30654bff34e3Sthurlow 	switch (cmd) {
30664bff34e3Sthurlow 	case _PC_FILESIZEBITS:
30674bff34e3Sthurlow 		ssp = smi->smi_share;
30684bff34e3Sthurlow 		if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)
30694bff34e3Sthurlow 			*valp = 64;
30704bff34e3Sthurlow 		else
30714bff34e3Sthurlow 			*valp = 32;
30724bff34e3Sthurlow 		break;
30734bff34e3Sthurlow 
30744bff34e3Sthurlow 	case _PC_LINK_MAX:
30754bff34e3Sthurlow 		/* We only ever report one link to an object */
30764bff34e3Sthurlow 		*valp = 1;
30774bff34e3Sthurlow 		break;
30784bff34e3Sthurlow 
30797568150aSgwr 	case _PC_ACL_ENABLED:
30807568150aSgwr 		/*
308102d09e03SGordon Ross 		 * Always indicate that ACLs are enabled and
308202d09e03SGordon Ross 		 * that we support ACE_T format, otherwise
308302d09e03SGordon Ross 		 * libsec will ask for ACLENT_T format data
308402d09e03SGordon Ross 		 * which we don't support.
30857568150aSgwr 		 */
30867568150aSgwr 		*valp = _ACL_ACE_ENABLED;
30877568150aSgwr 		break;
30887568150aSgwr 
30894bff34e3Sthurlow 	case _PC_SYMLINK_MAX:	/* No symlinks until we do Unix extensions */
30904bff34e3Sthurlow 		*valp = 0;
30914bff34e3Sthurlow 		break;
30924bff34e3Sthurlow 
309391d632c8Sgwr 	case _PC_XATTR_EXISTS:
309491d632c8Sgwr 		if (vfs->vfs_flag & VFS_XATTR) {
309591d632c8Sgwr 			*valp = smbfs_xa_exists(vp, cr);
309691d632c8Sgwr 			break;
309791d632c8Sgwr 		}
309891d632c8Sgwr 		return (EINVAL);
309991d632c8Sgwr 
310028162916SGordon Ross 	case _PC_SATTR_ENABLED:
310128162916SGordon Ross 	case _PC_SATTR_EXISTS:
310228162916SGordon Ross 		*valp = 1;
310328162916SGordon Ross 		break;
310428162916SGordon Ross 
31053b862e9aSRoger A. Faulkner 	case _PC_TIMESTAMP_RESOLUTION:
310602d09e03SGordon Ross 		/*
310702d09e03SGordon Ross 		 * Windows times are tenths of microseconds
310802d09e03SGordon Ross 		 * (multiples of 100 nanoseconds).
310902d09e03SGordon Ross 		 */
311002d09e03SGordon Ross 		*valp = 100L;
31113b862e9aSRoger A. Faulkner 		break;
31123b862e9aSRoger A. Faulkner 
31134bff34e3Sthurlow 	default:
31144bff34e3Sthurlow 		return (fs_pathconf(vp, cmd, valp, cr, ct));
31154bff34e3Sthurlow 	}
31164bff34e3Sthurlow 	return (0);
31174bff34e3Sthurlow }
31184bff34e3Sthurlow 
31197568150aSgwr /* ARGSUSED */
31207568150aSgwr static int
31217568150aSgwr smbfs_getsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr,
31227568150aSgwr 	caller_context_t *ct)
31237568150aSgwr {
31247568150aSgwr 	vfs_t *vfsp;
31257568150aSgwr 	smbmntinfo_t *smi;
312602d09e03SGordon Ross 	int	error;
31277568150aSgwr 	uint_t	mask;
31287568150aSgwr 
31297568150aSgwr 	vfsp = vp->v_vfsp;
31307568150aSgwr 	smi = VFTOSMI(vfsp);
31317568150aSgwr 
3132a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
31337568150aSgwr 		return (EIO);
31347568150aSgwr 
31357568150aSgwr 	if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
31367568150aSgwr 		return (EIO);
31377568150aSgwr 
31387568150aSgwr 	/*
31397568150aSgwr 	 * Our _pathconf indicates _ACL_ACE_ENABLED,
31407568150aSgwr 	 * so we should only see VSA_ACE, etc here.
31417568150aSgwr 	 * Note: vn_create asks for VSA_DFACLCNT,
31427568150aSgwr 	 * and it expects ENOSYS and empty data.
31437568150aSgwr 	 */
31447568150aSgwr 	mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT |
31457568150aSgwr 	    VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES);
31467568150aSgwr 	if (mask == 0)
31477568150aSgwr 		return (ENOSYS);
31487568150aSgwr 
314902d09e03SGordon Ross 	if (smi->smi_flags & SMI_ACL)
3150bd7c6f51SGordon Ross 		error = smbfs_acl_getvsa(vp, vsa, flag, cr);
315102d09e03SGordon Ross 	else
31527568150aSgwr 		error = ENOSYS;
31537568150aSgwr 
31547568150aSgwr 	if (error == ENOSYS)
31557568150aSgwr 		error = fs_fab_acl(vp, vsa, flag, cr, ct);
31567568150aSgwr 
31577568150aSgwr 	return (error);
31587568150aSgwr }
31597568150aSgwr 
31607568150aSgwr /* ARGSUSED */
31617568150aSgwr static int
31627568150aSgwr smbfs_setsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr,
31637568150aSgwr 	caller_context_t *ct)
31647568150aSgwr {
31657568150aSgwr 	vfs_t *vfsp;
31667568150aSgwr 	smbmntinfo_t *smi;
31677568150aSgwr 	int	error;
31687568150aSgwr 	uint_t	mask;
31697568150aSgwr 
31707568150aSgwr 	vfsp = vp->v_vfsp;
31717568150aSgwr 	smi = VFTOSMI(vfsp);
31727568150aSgwr 
3173a19609f8Sjv 	if (curproc->p_zone != smi->smi_zone_ref.zref_zone)
31747568150aSgwr 		return (EIO);
31757568150aSgwr 
31767568150aSgwr 	if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
31777568150aSgwr 		return (EIO);
31787568150aSgwr 
31797568150aSgwr 	/*
31807568150aSgwr 	 * Our _pathconf indicates _ACL_ACE_ENABLED,
31817568150aSgwr 	 * so we should only see VSA_ACE, etc here.
31827568150aSgwr 	 */
31837568150aSgwr 	mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT);
31847568150aSgwr 	if (mask == 0)
31857568150aSgwr 		return (ENOSYS);
31867568150aSgwr 
31877568150aSgwr 	if (vfsp->vfs_flag & VFS_RDONLY)
31887568150aSgwr 		return (EROFS);
31897568150aSgwr 
319002d09e03SGordon Ross 	/*
319102d09e03SGordon Ross 	 * Allow only the mount owner to do this.
319202d09e03SGordon Ross 	 * See comments at smbfs_access_rwx.
319302d09e03SGordon Ross 	 */
319402d09e03SGordon Ross 	error = secpolicy_vnode_setdac(cr, smi->smi_uid);
319502d09e03SGordon Ross 	if (error != 0)
319602d09e03SGordon Ross 		return (error);
319702d09e03SGordon Ross 
319802d09e03SGordon Ross 	if (smi->smi_flags & SMI_ACL)
3199bd7c6f51SGordon Ross 		error = smbfs_acl_setvsa(vp, vsa, flag, cr);
320002d09e03SGordon Ross 	else
32017568150aSgwr 		error = ENOSYS;
32027568150aSgwr 
32037568150aSgwr 	return (error);
32047568150aSgwr }
32054bff34e3Sthurlow 
32064bff34e3Sthurlow 
32074bff34e3Sthurlow /*
32084bff34e3Sthurlow  * XXX
32094bff34e3Sthurlow  * This op should eventually support PSARC 2007/268.
32104bff34e3Sthurlow  */
32114bff34e3Sthurlow static int
32124bff34e3Sthurlow smbfs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
32134bff34e3Sthurlow 	caller_context_t *ct)
32144bff34e3Sthurlow {
3215a19609f8Sjv 	if (curproc->p_zone != VTOSMI(vp)->smi_zone_ref.zref_zone)
32164bff34e3Sthurlow 		return (EIO);
32174bff34e3Sthurlow 
32184bff34e3Sthurlow 	if (VTOSMI(vp)->smi_flags & SMI_LLOCK)
32194bff34e3Sthurlow 		return (fs_shrlock(vp, cmd, shr, flag, cr, ct));
32204bff34e3Sthurlow 	else
32214bff34e3Sthurlow 		return (ENOSYS);
32224bff34e3Sthurlow }
3223