1 /*
2  * Copyright (c) 2000-2001 Boris Popov
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *    This product includes software developed by Boris Popov.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $Id: smbfs_vnops.c,v 1.128.36.1 2005/05/27 02:35:28 lindak Exp $
33  */
34 
35 /*
36  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
37  * Use is subject to license terms.
38  */
39 
40 #pragma ident	"%Z%%M%	%I%	%E% SMI"
41 
42 #include <sys/systm.h>
43 #include <sys/cred.h>
44 #include <sys/vnode.h>
45 #include <sys/vfs.h>
46 #include <sys/filio.h>
47 #include <sys/uio.h>
48 #include <sys/dirent.h>
49 #include <sys/errno.h>
50 #include <sys/sysmacros.h>
51 #include <sys/kmem.h>
52 #include <sys/cmn_err.h>
53 #include <sys/dnlc.h>
54 #include <sys/vfs_opreg.h>
55 #include <sys/policy.h>
56 
57 #include <netsmb/smb_osdep.h>
58 #include <netsmb/smb.h>
59 #include <netsmb/smb_conn.h>
60 #include <netsmb/smb_subr.h>
61 
62 #include <smbfs/smbfs.h>
63 #include <smbfs/smbfs_node.h>
64 #include <smbfs/smbfs_subr.h>
65 
66 #include <sys/fs/smbfs_ioctl.h>
67 #include <fs/fs_subr.h>
68 
69 /*
70  * These characters are illegal in NTFS file names.
71  * ref: http://support.microsoft.com/kb/147438
72  */
73 static const char illegal_chars[] = {
74 	'\\',	/* back slash */
75 	'/',	/* slash */
76 	':',	/* colon */
77 	'*',	/* asterisk */
78 	'?',	/* question mark */
79 	'"',	/* double quote */
80 	'<',	/* less than sign */
81 	'>',	/* greater than sign */
82 	'|',	/* vertical bar */
83 	0
84 };
85 
86 /*
87  * Turning this on causes nodes to be created in the cache
88  * during directory listings.  The "fast" claim is debatable,
89  * and the effects on the cache can be undesirable.
90  */
91 
92 /* local static function defines */
93 
94 static int	smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr,
95 			int dnlc, caller_context_t *);
96 static int	smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm,
97 			cred_t *cr, caller_context_t *);
98 static int	smbfssetattr(vnode_t *, struct vattr *, int, cred_t *);
99 static int	smbfs_accessx(void *, int, cred_t *);
100 static int	smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
101 			caller_context_t *);
102 /*
103  * These are the vnode ops routines which implement the vnode interface to
104  * the networked file system.  These routines just take their parameters,
105  * make them look networkish by putting the right info into interface structs,
106  * and then calling the appropriate remote routine(s) to do the work.
107  *
108  * Note on directory name lookup cacheing:  If we detect a stale fhandle,
109  * we purge the directory cache relative to that vnode.  This way, the
110  * user won't get burned by the cache repeatedly.  See <smbfs/smbnode.h> for
111  * more details on smbnode locking.
112  */
113 
114 static int	smbfs_open(vnode_t **, int, cred_t *, caller_context_t *);
115 static int	smbfs_close(vnode_t *, int, int, offset_t, cred_t *,
116 			caller_context_t *);
117 static int	smbfs_read(vnode_t *, struct uio *, int, cred_t *,
118 			caller_context_t *);
119 static int	smbfs_write(vnode_t *, struct uio *, int, cred_t *,
120 			caller_context_t *);
121 static int	smbfs_ioctl(vnode_t *, int, intptr_t, int, cred_t *, int *,
122 			caller_context_t *);
123 static int	smbfs_getattr(vnode_t *, struct vattr *, int, cred_t *,
124 			caller_context_t *);
125 static int	smbfs_setattr(vnode_t *, struct vattr *, int, cred_t *,
126 			caller_context_t *);
127 static int	smbfs_access(vnode_t *, int, int, cred_t *, caller_context_t *);
128 static int	smbfs_fsync(vnode_t *, int, cred_t *, caller_context_t *);
129 static void	smbfs_inactive(vnode_t *, cred_t *, caller_context_t *);
130 static int	smbfs_lookup(vnode_t *, char *, vnode_t **, struct pathname *,
131 			int, vnode_t *, cred_t *, caller_context_t *,
132 			int *, pathname_t *);
133 static int	smbfs_create(vnode_t *, char *, struct vattr *, enum vcexcl,
134 			int, vnode_t **, cred_t *, int, caller_context_t *,
135 			vsecattr_t *);
136 static int	smbfs_remove(vnode_t *, char *, cred_t *, caller_context_t *,
137 			int);
138 static int	smbfs_rename(vnode_t *, char *, vnode_t *, char *, cred_t *,
139 			caller_context_t *, int);
140 static int	smbfs_mkdir(vnode_t *, char *, struct vattr *, vnode_t **,
141 			cred_t *, caller_context_t *, int, vsecattr_t *);
142 static int	smbfs_rmdir(vnode_t *, char *, vnode_t *, cred_t *,
143 			caller_context_t *, int);
144 static int	smbfs_readdir(vnode_t *, struct uio *, cred_t *, int *,
145 			caller_context_t *, int);
146 static int	smbfs_rwlock(vnode_t *, int, caller_context_t *);
147 static void	smbfs_rwunlock(vnode_t *, int, caller_context_t *);
148 static int	smbfs_seek(vnode_t *, offset_t, offset_t *, caller_context_t *);
149 static int	smbfs_frlock(vnode_t *, int, struct flock64 *, int, offset_t,
150 			struct flk_callback *, cred_t *, caller_context_t *);
151 static int	smbfs_space(vnode_t *, int, struct flock64 *, int, offset_t,
152 			cred_t *, caller_context_t *);
153 static int	smbfs_pathconf(vnode_t *, int, ulong_t *, cred_t *,
154 			caller_context_t *);
155 static int	smbfs_setsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
156 			caller_context_t *);
157 static int	smbfs_getsecattr(vnode_t *, vsecattr_t *, int, cred_t *,
158 			caller_context_t *);
159 static int	smbfs_shrlock(vnode_t *, int, struct shrlock *, int, cred_t *,
160 			caller_context_t *);
161 
162 /* Dummy function to use until correct function is ported in */
163 int noop_vnodeop() {
164 	return (0);
165 }
166 
167 struct vnodeops *smbfs_vnodeops = NULL;
168 
169 /*
170  * Most unimplemented ops will return ENOSYS because of fs_nosys().
171  * The only ops where that won't work are ACCESS (due to open(2)
172  * failures) and ... (anything else left?)
173  */
174 const fs_operation_def_t smbfs_vnodeops_template[] = {
175 	{ VOPNAME_OPEN,		{ .vop_open = smbfs_open } },
176 	{ VOPNAME_CLOSE,	{ .vop_close = smbfs_close } },
177 	{ VOPNAME_READ,		{ .vop_read = smbfs_read } },
178 	{ VOPNAME_WRITE,	{ .vop_write = smbfs_write } },
179 	{ VOPNAME_IOCTL,	{ .vop_ioctl = smbfs_ioctl } },
180 	{ VOPNAME_GETATTR,	{ .vop_getattr = smbfs_getattr } },
181 	{ VOPNAME_SETATTR,	{ .vop_setattr = smbfs_setattr } },
182 	{ VOPNAME_ACCESS,	{ .vop_access = smbfs_access } },
183 	{ VOPNAME_LOOKUP,	{ .vop_lookup = smbfs_lookup } },
184 	{ VOPNAME_CREATE,	{ .vop_create = smbfs_create } },
185 	{ VOPNAME_REMOVE,	{ .vop_remove = smbfs_remove } },
186 	{ VOPNAME_LINK,		{ .error = fs_nosys } }, /* smbfs_link, */
187 	{ VOPNAME_RENAME,	{ .vop_rename = smbfs_rename } },
188 	{ VOPNAME_MKDIR,	{ .vop_mkdir = smbfs_mkdir } },
189 	{ VOPNAME_RMDIR,	{ .vop_rmdir = smbfs_rmdir } },
190 	{ VOPNAME_READDIR,	{ .vop_readdir = smbfs_readdir } },
191 	{ VOPNAME_SYMLINK,	{ .error = fs_nosys } }, /* smbfs_symlink, */
192 	{ VOPNAME_READLINK,	{ .error = fs_nosys } }, /* smbfs_readlink, */
193 	{ VOPNAME_FSYNC,	{ .vop_fsync = smbfs_fsync } },
194 	{ VOPNAME_INACTIVE,	{ .vop_inactive = smbfs_inactive } },
195 	{ VOPNAME_FID,		{ .error = fs_nosys } }, /* smbfs_fid, */
196 	{ VOPNAME_RWLOCK,	{ .vop_rwlock = smbfs_rwlock } },
197 	{ VOPNAME_RWUNLOCK,	{ .vop_rwunlock = smbfs_rwunlock } },
198 	{ VOPNAME_SEEK,		{ .vop_seek = smbfs_seek } },
199 	{ VOPNAME_FRLOCK,	{ .vop_frlock = smbfs_frlock } },
200 	{ VOPNAME_SPACE,	{ .vop_space = smbfs_space } },
201 	{ VOPNAME_REALVP,	{ .error = fs_nosys } }, /* smbfs_realvp, */
202 	{ VOPNAME_GETPAGE,	{ .error = fs_nosys } }, /* smbfs_getpage, */
203 	{ VOPNAME_PUTPAGE,	{ .error = fs_nosys } }, /* smbfs_putpage, */
204 	{ VOPNAME_MAP,		{ .error = fs_nosys } }, /* smbfs_map, */
205 	{ VOPNAME_ADDMAP,	{ .error = fs_nosys } }, /* smbfs_addmap, */
206 	{ VOPNAME_DELMAP,	{ .error = fs_nosys } }, /* smbfs_delmap, */
207 	{ VOPNAME_DUMP,		{ .error = fs_nosys } }, /* smbfs_dump, */
208 	{ VOPNAME_PATHCONF,	{ .vop_pathconf = smbfs_pathconf } },
209 	{ VOPNAME_PAGEIO,	{ .error = fs_nosys } }, /* smbfs_pageio, */
210 	{ VOPNAME_SETSECATTR,	{ .vop_setsecattr = smbfs_setsecattr } },
211 	{ VOPNAME_GETSECATTR,	{ .vop_getsecattr = smbfs_getsecattr } },
212 	{ VOPNAME_SHRLOCK,	{ .vop_shrlock = smbfs_shrlock } },
213 	{ NULL, NULL }
214 };
215 
216 /*
217  * XXX
218  * When new and relevant functionality is enabled, we should be
219  * calling vfs_set_feature() to inform callers that pieces of
220  * functionality are available, per PSARC 2007/227, e.g.
221  *
222  * VFSFT_XVATTR            Supports xvattr for attrs
223  * VFSFT_CASEINSENSITIVE   Supports case-insensitive
224  * VFSFT_NOCASESENSITIVE   NOT case-sensitive
225  * VFSFT_DIRENTFLAGS       Supports dirent flags
226  * VFSFT_ACLONCREATE       Supports ACL on create
227  * VFSFT_ACEMASKONACCESS   Can use ACEMASK for access
228  */
229 /* ARGSUSED */
230 static int
231 smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
232 {
233 	struct vattr	va;
234 	smbnode_t	*np;
235 	vnode_t		*vp;
236 	u_int32_t	rights, rightsrcvd;
237 	u_int16_t	fid, oldfid;
238 	struct smb_cred scred;
239 	smbmntinfo_t	*smi;
240 	cred_t		*oldcr;
241 	int		attrcacheupdated = 0;
242 	int		tmperror;
243 	int		error = 0;
244 
245 	vp = *vpp;
246 	np = VTOSMB(vp);
247 	smi = VTOSMI(vp);
248 
249 	if (curproc->p_zone != smi->smi_zone)
250 		return (EIO);
251 
252 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
253 		return (EIO);
254 
255 	if (vp->v_type != VREG && vp->v_type != VDIR) { /* XXX VLNK? */
256 		SMBVDEBUG("open eacces vtype=%d\n", vp->v_type);
257 		return (EACCES);
258 	}
259 
260 	/*
261 	 * Get exclusive access to n_fid and related stuff.
262 	 * No returns after this until out.
263 	 */
264 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp)))
265 		return (EINTR);
266 	smb_credinit(&scred, curproc, cr);
267 
268 	/*
269 	 * Directory open is easy.
270 	 */
271 	if (vp->v_type == VDIR) {
272 		np->n_dirrefs++;
273 		goto have_fid;
274 	}
275 
276 	/*
277 	 * If caller specified O_TRUNC/FTRUNC, then be sure to set
278 	 * FWRITE (to drive successful setattr(size=0) after open)
279 	 */
280 	if (flag & FTRUNC)
281 		flag |= FWRITE;
282 
283 	/*
284 	 * If we already have it open, check to see if current rights
285 	 * are sufficient for this open.
286 	 */
287 	if (np->n_fidrefs) {
288 		int upgrade = 0;
289 
290 		/* BEGIN CSTYLED */
291 		if ((flag & FWRITE) &&
292 		    !(np->n_rights & (SA_RIGHT_FILE_WRITE_DATA |
293 				GENERIC_RIGHT_ALL_ACCESS |
294 				GENERIC_RIGHT_WRITE_ACCESS)))
295 			upgrade = 1;
296 		if ((flag & FREAD) &&
297 		    !(np->n_rights & (SA_RIGHT_FILE_READ_DATA |
298 				GENERIC_RIGHT_ALL_ACCESS |
299 				GENERIC_RIGHT_READ_ACCESS)))
300 			upgrade = 1;
301 		/* END CSTYLED */
302 		if (!upgrade) {
303 			/*
304 			 *  the existing open is good enough
305 			 */
306 			np->n_fidrefs++;
307 			goto have_fid;
308 		}
309 	}
310 	rights = np->n_fidrefs ? np->n_rights : 0;
311 
312 	/*
313 	 * we always ask for READ_CONTROL so we can always get the
314 	 * owner/group IDs to satisfy a stat.
315 	 * XXX: verify that works with "drop boxes"
316 	 */
317 	rights |= STD_RIGHT_READ_CONTROL_ACCESS;
318 	if ((flag & FREAD))
319 		rights |= SA_RIGHT_FILE_READ_DATA;
320 	if ((flag & FWRITE))
321 		rights |= SA_RIGHT_FILE_APPEND_DATA | SA_RIGHT_FILE_WRITE_DATA;
322 
323 	/* XXX: open gets the current size, but we don't use it. */
324 	error = smbfs_smb_open(np, rights, &scred, &attrcacheupdated, &fid,
325 	    NULL, 0, 0, NULL, &rightsrcvd);
326 	if (error)
327 		goto out;
328 
329 	/*
330 	 * We have a new FID and access rights.
331 	 */
332 	oldfid = np->n_fid;
333 	np->n_fid = fid;
334 	np->n_rights = rightsrcvd;
335 	np->n_fidrefs++;
336 	if (np->n_fidrefs > 1) {
337 		/*
338 		 * We already had it open (presumably because
339 		 * it was open with insufficient rights.)
340 		 * Close old wire-open.
341 		 */
342 		tmperror = smbfs_smb_close(smi->smi_share,
343 		    oldfid, &np->n_mtime, &scred);
344 		if (tmperror)
345 			SMBVDEBUG("error %d closing %s\n",
346 			    tmperror, np->n_rpath);
347 	}
348 
349 	/*
350 	 * This thread did the open.
351 	 * Save our credentials too.
352 	 */
353 	mutex_enter(&np->r_statelock);
354 	oldcr = np->r_cred;
355 	np->r_cred = cr;
356 	crhold(cr);
357 	if (oldcr)
358 		crfree(oldcr);
359 	mutex_exit(&np->r_statelock);
360 
361 have_fid:
362 	/* Get attributes (maybe). */
363 
364 
365 	/* Darwin (derived) code. */
366 
367 	va.va_mask = AT_MTIME;
368 	if (np->n_flag & NMODIFIED)
369 		smbfs_attr_cacheremove(np);
370 
371 	/*
372 	 * Try to get attributes, but don't bail on error.
373 	 * We already hold r_lkserlock/reader so note:
374 	 * this call will recursively take r_lkserlock.
375 	 */
376 	tmperror = smbfsgetattr(vp, &va, cr);
377 	if (tmperror)
378 		SMBERROR("getattr failed, error=%d", tmperror);
379 	else
380 		np->n_mtime.tv_sec = va.va_mtime.tv_sec;
381 
382 out:
383 	smb_credrele(&scred);
384 	smbfs_rw_exit(&np->r_lkserlock);
385 	return (error);
386 }
387 
388 /*ARGSUSED*/
389 static int
390 smbfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
391 	caller_context_t *ct)
392 {
393 	smbnode_t	*np;
394 	int		error = 0;
395 	struct smb_cred scred;
396 
397 	np = VTOSMB(vp);
398 
399 	/*
400 	 * Don't "bail out" for VFS_UNMOUNTED here,
401 	 * as we want to do cleanup, etc.
402 	 */
403 
404 	/*
405 	 * zone_enter(2) prevents processes from changing zones with SMBFS files
406 	 * open; if we happen to get here from the wrong zone we can't do
407 	 * anything over the wire.
408 	 */
409 	if (VTOSMI(vp)->smi_zone != curproc->p_zone) {
410 		/*
411 		 * We could attempt to clean up locks, except we're sure
412 		 * that the current process didn't acquire any locks on
413 		 * the file: any attempt to lock a file belong to another zone
414 		 * will fail, and one can't lock an SMBFS file and then change
415 		 * zones, as that fails too.
416 		 *
417 		 * Returning an error here is the sane thing to do.  A
418 		 * subsequent call to VN_RELE() which translates to a
419 		 * smbfs_inactive() will clean up state: if the zone of the
420 		 * vnode's origin is still alive and kicking, an async worker
421 		 * thread will handle the request (from the correct zone), and
422 		 * everything (minus the final smbfs_getattr_otw() call) should
423 		 * be OK. If the zone is going away smbfs_async_inactive() will
424 		 * throw away cached pages inline.
425 		 */
426 		return (EIO);
427 	}
428 
429 	/*
430 	 * If we are using local locking for this filesystem, then
431 	 * release all of the SYSV style record locks.  Otherwise,
432 	 * we are doing network locking and we need to release all
433 	 * of the network locks.  All of the locks held by this
434 	 * process on this file are released no matter what the
435 	 * incoming reference count is.
436 	 */
437 	if (VTOSMI(vp)->smi_flags & SMI_LLOCK) {
438 		cleanlocks(vp, ttoproc(curthread)->p_pid, 0);
439 		cleanshares(vp, ttoproc(curthread)->p_pid);
440 	}
441 
442 	if (count > 1)
443 		return (0);
444 	/*
445 	 * OK, do "last close" stuff.
446 	 */
447 
448 
449 	/*
450 	 * Do the CIFS close.
451 	 * Darwin code
452 	 */
453 
454 	/*
455 	 * Exclusive lock for modifying n_fid stuff.
456 	 * Don't want this one ever interruptible.
457 	 */
458 	(void) smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, 0);
459 	smb_credinit(&scred, curproc, cr);
460 
461 	error = 0;
462 	if (vp->v_type == VDIR) {
463 		struct smbfs_fctx *fctx;
464 		ASSERT(np->n_dirrefs > 0);
465 		if (--np->n_dirrefs)
466 			goto out;
467 		if ((fctx = np->n_dirseq) != NULL) {
468 			np->n_dirseq = NULL;
469 			error = smbfs_smb_findclose(fctx, &scred);
470 		}
471 	} else {
472 		uint16_t ofid;
473 		ASSERT(np->n_fidrefs > 0);
474 		if (--np->n_fidrefs)
475 			goto out;
476 		if ((ofid = np->n_fid) != SMB_FID_UNUSED) {
477 			np->n_fid = SMB_FID_UNUSED;
478 			error = smbfs_smb_close(np->n_mount->smi_share,
479 			    ofid, NULL, &scred);
480 		}
481 	}
482 	if (error) {
483 		SMBERROR("error %d closing %s\n",
484 		    error, np->n_rpath);
485 	}
486 
487 	if (np->n_flag & NATTRCHANGED)
488 		smbfs_attr_cacheremove(np);
489 
490 out:
491 	smb_credrele(&scred);
492 	smbfs_rw_exit(&np->r_lkserlock);
493 
494 	/* don't return any errors */
495 	return (0);
496 }
497 
498 /* ARGSUSED */
499 static int
500 smbfs_read(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
501 	caller_context_t *ct)
502 {
503 	int		error;
504 	struct vattr	va;
505 	smbmntinfo_t	*smi;
506 	smbnode_t	*np;
507 	/* u_offset_t	off; */
508 	/* offset_t	diff; */
509 
510 	np = VTOSMB(vp);
511 	smi = VTOSMI(vp);
512 
513 	if (curproc->p_zone != smi->smi_zone)
514 		return (EIO);
515 
516 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
517 		return (EIO);
518 
519 	ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER));
520 
521 	if (vp->v_type != VREG)
522 		return (EISDIR);
523 
524 	if (uiop->uio_resid == 0)
525 		return (0);
526 
527 	/*
528 	 * Like NFS3, just check for 63-bit overflow.
529 	 * Our SMB layer takes care to return EFBIG
530 	 * when it has to fallback to a 32-bit call.
531 	 */
532 	if (uiop->uio_loffset < 0 ||
533 	    uiop->uio_loffset + uiop->uio_resid < 0)
534 		return (EINVAL);
535 
536 	/* Shared lock for n_fid use in smbfs_readvnode */
537 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
538 		return (EINTR);
539 
540 	/* get vnode attributes from server */
541 	va.va_mask = AT_SIZE | AT_MTIME;
542 	if (error = smbfsgetattr(vp, &va, cr))
543 		goto out;
544 
545 	/* should probably update mtime with mtime from server here */
546 
547 	/*
548 	 * Darwin had a loop here that handled paging stuff.
549 	 * Solaris does paging differently, so no loop needed.
550 	 */
551 	error = smbfs_readvnode(vp, uiop, cr, &va);
552 
553 out:
554 	smbfs_rw_exit(&np->r_lkserlock);
555 	return (error);
556 
557 }
558 
559 
560 /* ARGSUSED */
561 static int
562 smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr,
563 	caller_context_t *ct)
564 {
565 	int		error;
566 	smbmntinfo_t 	*smi;
567 	smbnode_t 	*np;
568 	int		timo = SMBWRTTIMO;
569 
570 	np = VTOSMB(vp);
571 	smi = VTOSMI(vp);
572 
573 	if (curproc->p_zone != smi->smi_zone)
574 		return (EIO);
575 
576 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
577 		return (EIO);
578 
579 	ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_WRITER));
580 
581 	if (vp->v_type != VREG)
582 		return (EISDIR);
583 
584 	if (uiop->uio_resid == 0)
585 		return (0);
586 
587 	/* Shared lock for n_fid use in smbfs_writevnode */
588 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
589 		return (EINTR);
590 
591 
592 	/*
593 	 * Darwin had a loop here that handled paging stuff.
594 	 * Solaris does paging differently, so no loop needed.
595 	 */
596 	error = smbfs_writevnode(vp, uiop, cr, ioflag, timo);
597 
598 	smbfs_rw_exit(&np->r_lkserlock);
599 	return (error);
600 
601 }
602 
603 
604 /* ARGSUSED */
605 static int
606 smbfs_ioctl(vnode_t *vp, int cmd, intptr_t arg, int flag,
607 	cred_t *cr, int *rvalp,	caller_context_t *ct)
608 {
609 	int		error;
610 	smbmntinfo_t 	*smi;
611 
612 	smi = VTOSMI(vp);
613 
614 	if (curproc->p_zone != smi->smi_zone)
615 		return (EIO);
616 
617 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
618 		return (EIO);
619 
620 	switch (cmd) {
621 		/* First three from ZFS. XXX - need these? */
622 
623 	case _FIOFFS:
624 		error = smbfs_fsync(vp, 0, cr, ct);
625 		break;
626 
627 		/*
628 		 * The following two ioctls are used by bfu.
629 		 * Silently ignore to avoid bfu errors.
630 		 */
631 	case _FIOGDIO:
632 	case _FIOSDIO:
633 		error = 0;
634 		break;
635 
636 #ifdef NOT_YET	/* XXX - from the NFS code. */
637 	case _FIODIRECTIO:
638 		error = smbfs_directio(vp, (int)arg, cr);
639 #endif
640 
641 		/*
642 		 * Allow get/set with "raw" security descriptor (SD) data.
643 		 * Useful for testing, diagnosing idmap problems, etc.
644 		 */
645 	case SMBFSIO_GETSD:
646 		error = smbfs_ioc_getsd(vp, arg, flag, cr);
647 		break;
648 
649 	case SMBFSIO_SETSD:
650 		error = smbfs_ioc_setsd(vp, arg, flag, cr);
651 		break;
652 
653 	default:
654 		error = ENOTTY;
655 		break;
656 	}
657 
658 	return (error);
659 }
660 
661 
662 /*
663  * Return either cached or remote attributes. If get remote attr
664  * use them to check and invalidate caches, then cache the new attributes.
665  *
666  * XXX
667  * This op should eventually support PSARC 2007/315, Extensible Attribute
668  * Interfaces, for richer metadata.
669  */
670 /* ARGSUSED */
671 static int
672 smbfs_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
673 	caller_context_t *ct)
674 {
675 	smbnode_t *np;
676 	smbmntinfo_t *smi;
677 
678 	smi = VTOSMI(vp);
679 
680 	if (curproc->p_zone != smi->smi_zone)
681 		return (EIO);
682 
683 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
684 		return (EIO);
685 
686 	/*
687 	 * If it has been specified that the return value will
688 	 * just be used as a hint, and we are only being asked
689 	 * for size, fsid or rdevid, then return the client's
690 	 * notion of these values without checking to make sure
691 	 * that the attribute cache is up to date.
692 	 * The whole point is to avoid an over the wire GETATTR
693 	 * call.
694 	 */
695 	np = VTOSMB(vp);
696 	if (flags & ATTR_HINT) {
697 		if (vap->va_mask ==
698 		    (vap->va_mask & (AT_SIZE | AT_FSID | AT_RDEV))) {
699 			mutex_enter(&np->r_statelock);
700 			if (vap->va_mask | AT_SIZE)
701 				vap->va_size = np->r_size;
702 			if (vap->va_mask | AT_FSID)
703 				vap->va_fsid = np->r_attr.va_fsid;
704 			if (vap->va_mask | AT_RDEV)
705 				vap->va_rdev = np->r_attr.va_rdev;
706 			mutex_exit(&np->r_statelock);
707 			return (0);
708 		}
709 	}
710 
711 
712 	return (smbfsgetattr(vp, vap, cr));
713 }
714 
715 /*
716  * Mostly from Darwin smbfs_getattr()
717  */
718 int
719 smbfsgetattr(vnode_t *vp, struct vattr *vap, cred_t *cr)
720 {
721 	int error;
722 	smbnode_t *np;
723 	struct smb_cred scred;
724 	struct smbfattr fattr;
725 
726 	ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone);
727 
728 	np = VTOSMB(vp);
729 
730 	/*
731 	 * If we've got cached attributes, we're done, otherwise go
732 	 * to the server to get attributes, which will update the cache
733 	 * in the process.
734 	 *
735 	 * This section from Darwin smbfs_getattr,
736 	 * but then modified a lot.
737 	 */
738 	error = smbfs_attr_cachelookup(vp, vap);
739 	if (error != ENOENT)
740 		return (error);
741 
742 	/* Shared lock for (possible) n_fid use. */
743 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
744 		return (EINTR);
745 	smb_credinit(&scred, curproc, cr);
746 
747 	error = smbfs_smb_getfattr(np, &fattr, &scred);
748 
749 	smb_credrele(&scred);
750 	smbfs_rw_exit(&np->r_lkserlock);
751 
752 	if (!error) {
753 		smbfs_attr_cacheenter(vp, &fattr);
754 		error = smbfs_attr_cachelookup(vp, vap);
755 	}
756 	return (error);
757 }
758 
759 /*
760  * XXX
761  * This op should eventually support PSARC 2007/315, Extensible Attribute
762  * Interfaces, for richer metadata.
763  */
764 /*ARGSUSED4*/
765 static int
766 smbfs_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr,
767 		caller_context_t *ct)
768 {
769 	int		error;
770 	uint_t		mask;
771 	struct vattr	oldva;
772 	smbmntinfo_t	*smi;
773 
774 	smi = VTOSMI(vp);
775 
776 	if (curproc->p_zone != smi->smi_zone)
777 		return (EIO);
778 
779 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
780 		return (EIO);
781 
782 	mask = vap->va_mask;
783 	if (mask & AT_NOSET)
784 		return (EINVAL);
785 
786 	oldva.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
787 	error = smbfsgetattr(vp, &oldva, cr);
788 	if (error)
789 		return (error);
790 
791 	error = secpolicy_vnode_setattr(cr, vp, vap, &oldva, flags,
792 	    smbfs_accessx, vp);
793 	if (error)
794 		return (error);
795 
796 	return (smbfssetattr(vp, vap, flags, cr));
797 }
798 
799 /*
800  * Mostly from Darwin smbfs_setattr()
801  * but then modified a lot.
802  */
803 /* ARGSUSED */
804 static int
805 smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr)
806 {
807 	int		error = 0;
808 	smbnode_t	*np = VTOSMB(vp);
809 	smbmntinfo_t	*smi = VTOSMI(vp);
810 	uint_t		mask = vap->va_mask;
811 	struct timespec	*mtime, *atime;
812 	struct smb_cred	scred;
813 	int		cerror, modified = 0;
814 	unsigned short	fid;
815 	int have_fid = 0;
816 	uint32_t rights = 0;
817 
818 	ASSERT(curproc->p_zone == smi->smi_zone);
819 
820 	/*
821 	 * If our caller is trying to set multiple attributes, they
822 	 * can make no assumption about what order they are done in.
823 	 * Here we try to do them in order of decreasing likelihood
824 	 * of failure, just to minimize the chance we'll wind up
825 	 * with a partially complete request.
826 	 */
827 
828 	/* Shared lock for (possible) n_fid use. */
829 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp)))
830 		return (EINTR);
831 	smb_credinit(&scred, curproc, cr);
832 
833 	/*
834 	 * Will we need an open handle for this setattr?
835 	 * If so, what rights will we need?
836 	 */
837 	if (mask & (AT_ATIME | AT_MTIME)) {
838 		rights |=
839 		    SA_RIGHT_FILE_WRITE_ATTRIBUTES |
840 		    GENERIC_RIGHT_ALL_ACCESS |
841 		    GENERIC_RIGHT_WRITE_ACCESS;
842 	}
843 	if (mask & AT_SIZE) {
844 		rights |=
845 		    SA_RIGHT_FILE_WRITE_DATA |
846 		    SA_RIGHT_FILE_APPEND_DATA;
847 		/*
848 		 * Only SIZE requires a handle.
849 		 * XXX May be more reliable to just
850 		 * always get the file handle here.
851 		 */
852 		error = smbfs_smb_tmpopen(np, rights, &scred, &fid);
853 		if (error) {
854 			SMBVDEBUG("error %d opening %s\n",
855 			    error, np->n_rpath);
856 			goto out;
857 		}
858 		have_fid = 1;
859 	}
860 
861 
862 	/*
863 	 * If the server supports the UNIX extensions, right here is where
864 	 * we'd support changes to uid, gid, mode, and possibly va_flags.
865 	 * For now we claim to have made any such changes.
866 	 */
867 
868 	if (mask & AT_SIZE) {
869 		/*
870 		 * If the new file size is less than what the client sees as
871 		 * the file size, then just change the size and invalidate
872 		 * the pages.
873 		 * I am commenting this code at present because the function
874 		 * smbfs_putapage() is not yet implemented.
875 		 */
876 
877 		/*
878 		 * Set the file size to vap->va_size.
879 		 */
880 		ASSERT(have_fid);
881 		error = smbfs_smb_setfsize(np, fid, vap->va_size, &scred);
882 		if (error) {
883 			SMBVDEBUG("setsize error %d file %s\n",
884 			    error, np->n_rpath);
885 		} else {
886 			/*
887 			 * Darwin had code here to zero-extend.
888 			 * Tests indicate the server will zero-fill,
889 			 * so looks like we don't need to do this.
890 			 * Good thing, as this could take forever.
891 			 */
892 			mutex_enter(&np->r_statelock);
893 			np->r_size = vap->va_size;
894 			mutex_exit(&np->r_statelock);
895 			modified = 1;
896 		}
897 	}
898 
899 	/*
900 	 * XXX: When Solaris has create_time, set that too.
901 	 * Note: create_time is different from ctime.
902 	 */
903 	mtime = ((mask & AT_MTIME) ? &vap->va_mtime : 0);
904 	atime = ((mask & AT_ATIME) ? &vap->va_atime : 0);
905 
906 	if (mtime || atime) {
907 		/*
908 		 * If file is opened with write-attributes capability,
909 		 * we use handle-based calls.  If not, we use path-based ones.
910 		 */
911 		if (have_fid) {
912 			error = smbfs_smb_setfattr(np, fid,
913 			    np->n_dosattr, mtime, atime, &scred);
914 		} else {
915 			error = smbfs_smb_setpattr(np,
916 			    np->n_dosattr, mtime, atime, &scred);
917 		}
918 		if (error) {
919 			SMBVDEBUG("set times error %d file %s\n",
920 			    error, np->n_rpath);
921 		} else {
922 			/* XXX: set np->n_mtime, etc? */
923 			modified = 1;
924 		}
925 	}
926 
927 out:
928 	if (modified) {
929 		/*
930 		 * Invalidate attribute cache in case if server doesn't set
931 		 * required attributes.
932 		 */
933 		smbfs_attr_cacheremove(np);
934 		/*
935 		 * XXX Darwin called _getattr here to
936 		 * update the mtime.  Should we?
937 		 */
938 	}
939 
940 	if (have_fid) {
941 		cerror = smbfs_smb_tmpclose(np, fid, &scred);
942 		if (cerror)
943 			SMBERROR("error %d closing %s\n",
944 			    cerror, np->n_rpath);
945 	}
946 
947 	smb_credrele(&scred);
948 	smbfs_rw_exit(&np->r_lkserlock);
949 
950 	return (error);
951 }
952 
953 /*
954  * smbfs_access_rwx()
955  * Common function for smbfs_access, etc.
956  *
957  * The security model implemented by the FS is unusual
958  * due to our "single user mounts" restriction.
959  *
960  * All access under a given mount point uses the CIFS
961  * credentials established by the owner of the mount.
962  * The Unix uid/gid/mode information is not (easily)
963  * provided by CIFS, and is instead fabricated using
964  * settings held in the mount structure.
965  *
966  * Most access checking is handled by the CIFS server,
967  * but we need sufficient Unix access checks here to
968  * prevent other local Unix users from having access
969  * to objects under this mount that the uid/gid/mode
970  * settings in the mount would not allow.
971  *
972  * With this model, there is a case where we need the
973  * ability to do an access check before we have the
974  * vnode for an object.  This function takes advantage
975  * of the fact that the uid/gid/mode is per mount, and
976  * avoids the need for a vnode.
977  *
978  * We still (sort of) need a vnode when we call
979  * secpolicy_vnode_access, but that only uses
980  * the vtype field, so we can use a pair of fake
981  * vnodes that have only v_type filled in.
982  *
983  * XXX: Later, add a new secpolicy_vtype_access()
984  * that takes the vtype instead of a vnode, and
985  * get rid of the tmpl_vxxx fake vnodes below.
986  */
987 static int
988 smbfs_access_rwx(vfs_t *vfsp, int vtype, int mode, cred_t *cr)
989 {
990 	/* See the secpolicy call below. */
991 	static const vnode_t tmpl_vdir = { .v_type = VDIR };
992 	static const vnode_t tmpl_vreg = { .v_type = VREG };
993 	vattr_t		va;
994 	vnode_t		*tvp;
995 	struct smbmntinfo *smi = VFTOSMI(vfsp);
996 	int shift = 0;
997 
998 	/*
999 	 * Build our (fabricated) vnode attributes.
1000 	 * XXX: Could make these templates in the
1001 	 * per-mount struct and use them here.
1002 	 */
1003 	bzero(&va, sizeof (va));
1004 	va.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID;
1005 	va.va_type = vtype;
1006 	va.va_mode = (vtype == VDIR) ?
1007 	    smi->smi_args.dir_mode :
1008 	    smi->smi_args.file_mode;
1009 	va.va_uid = smi->smi_args.uid;
1010 	va.va_gid = smi->smi_args.gid;
1011 
1012 	/*
1013 	 * Disallow write attempts on read-only file systems,
1014 	 * unless the file is a device or fifo node.  Note:
1015 	 * Inline vn_is_readonly and IS_DEVVP here because
1016 	 * we may not have a vnode ptr.  Original expr. was:
1017 	 * (mode & VWRITE) && vn_is_readonly(vp) && !IS_DEVVP(vp))
1018 	 */
1019 	if ((mode & VWRITE) &&
1020 	    (vfsp->vfs_flag & VFS_RDONLY) &&
1021 	    !(vtype == VCHR || vtype == VBLK || vtype == VFIFO))
1022 		return (EROFS);
1023 
1024 	/*
1025 	 * Disallow attempts to access mandatory lock files.
1026 	 * Similarly, expand MANDLOCK here.
1027 	 * XXX: not sure we need this.
1028 	 */
1029 	if ((mode & (VWRITE | VREAD | VEXEC)) &&
1030 	    va.va_type == VREG && MANDMODE(va.va_mode))
1031 		return (EACCES);
1032 
1033 	/*
1034 	 * Access check is based on only
1035 	 * one of owner, group, public.
1036 	 * If not owner, then check group.
1037 	 * If not a member of the group,
1038 	 * then check public access.
1039 	 */
1040 	if (crgetuid(cr) != va.va_uid) {
1041 		shift += 3;
1042 		if (!groupmember(va.va_gid, cr))
1043 			shift += 3;
1044 	}
1045 	mode &= ~(va.va_mode << shift);
1046 	if (mode == 0)
1047 		return (0);
1048 
1049 	/*
1050 	 * We need a vnode for secpolicy_vnode_access,
1051 	 * but the only thing it looks at is v_type,
1052 	 * so pass one of the templates above.
1053 	 */
1054 	tvp = (va.va_type == VDIR) ?
1055 	    (vnode_t *)&tmpl_vdir :
1056 	    (vnode_t *)&tmpl_vreg;
1057 	return (secpolicy_vnode_access(cr, tvp, va.va_uid, mode));
1058 }
1059 
1060 /*
1061  * See smbfs_setattr
1062  */
1063 static int
1064 smbfs_accessx(void *arg, int mode, cred_t *cr)
1065 {
1066 	vnode_t *vp = arg;
1067 	/*
1068 	 * Note: The caller has checked the current zone,
1069 	 * the SMI_DEAD and VFS_UNMOUNTED flags, etc.
1070 	 */
1071 	return (smbfs_access_rwx(vp->v_vfsp, vp->v_type, mode, cr));
1072 }
1073 
1074 /*
1075  * XXX
1076  * This op should support PSARC 2007/403, Modified Access Checks for CIFS
1077  */
1078 /* ARGSUSED */
1079 static int
1080 smbfs_access(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
1081 {
1082 	vfs_t		*vfsp;
1083 	smbmntinfo_t	*smi;
1084 
1085 	vfsp = vp->v_vfsp;
1086 	smi = VFTOSMI(vfsp);
1087 
1088 	if (curproc->p_zone != smi->smi_zone)
1089 		return (EIO);
1090 
1091 	if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
1092 		return (EIO);
1093 
1094 	return (smbfs_access_rwx(vfsp, vp->v_type, mode, cr));
1095 }
1096 
1097 
1098 /*
1099  * Flush local dirty pages to stable storage on the server.
1100  *
1101  * If FNODSYNC is specified, then there is nothing to do because
1102  * metadata changes are not cached on the client before being
1103  * sent to the server.
1104  *
1105  * Currently, this is a no-op since we don't cache data, either.
1106  */
1107 /* ARGSUSED */
1108 static int
1109 smbfs_fsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
1110 {
1111 	int		error = 0;
1112 	smbmntinfo_t	*smi;
1113 
1114 	smi = VTOSMI(vp);
1115 
1116 	if (curproc->p_zone != smi->smi_zone)
1117 		return (EIO);
1118 
1119 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
1120 		return (EIO);
1121 
1122 	if ((syncflag & FNODSYNC) || IS_SWAPVP(vp))
1123 		return (0);
1124 
1125 	return (error);
1126 }
1127 
1128 /*
1129  * Last reference to vnode went away.
1130  */
1131 /* ARGSUSED */
1132 static void
1133 smbfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
1134 {
1135 	smbnode_t	*np;
1136 
1137 	/*
1138 	 * Don't "bail out" for VFS_UNMOUNTED here,
1139 	 * as we want to do cleanup, etc.
1140 	 * See also pcfs_inactive
1141 	 */
1142 
1143 	np = VTOSMB(vp);
1144 
1145 	/*
1146 	 * If this is coming from the wrong zone, we let someone in the right
1147 	 * zone take care of it asynchronously.  We can get here due to
1148 	 * VN_RELE() being called from pageout() or fsflush().  This call may
1149 	 * potentially turn into an expensive no-op if, for instance, v_count
1150 	 * gets incremented in the meantime, but it's still correct.
1151 	 */
1152 
1153 	/*
1154 	 * Some paranoia from the Darwin code:
1155 	 * Make sure the FID was closed.
1156 	 * If we see this, it's a bug!
1157 	 *
1158 	 * No rw_enter here, as this should be the
1159 	 * last ref, and we're just looking...
1160 	 */
1161 	if (np->n_fidrefs > 0) {
1162 		SMBVDEBUG("opencount %d fid %d file %s\n",
1163 		    np->n_fidrefs, np->n_fid, np->n_rpath);
1164 	}
1165 	if (np->n_dirrefs > 0) {
1166 		uint_t fid = (np->n_dirseq) ?
1167 		    np->n_dirseq->f_Sid : 0;
1168 		SMBVDEBUG("opencount %d fid %d dir %s\n",
1169 		    np->n_dirrefs, fid, np->n_rpath);
1170 	}
1171 
1172 	smb_addfree(np);
1173 }
1174 
1175 /*
1176  * Remote file system operations having to do with directory manipulation.
1177  */
1178 /* ARGSUSED */
1179 static int
1180 smbfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp,
1181 	int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
1182 	int *direntflags, pathname_t *realpnp)
1183 {
1184 	int		error;
1185 	smbnode_t	*dnp;
1186 	smbmntinfo_t	*smi;
1187 
1188 	smi = VTOSMI(dvp);
1189 
1190 	if (curproc->p_zone != smi->smi_zone)
1191 		return (EPERM);
1192 
1193 	if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
1194 		return (EIO);
1195 
1196 	dnp = VTOSMB(dvp);
1197 	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_READER, SMBINTR(dvp))) {
1198 		error = EINTR;
1199 		goto out;
1200 	}
1201 
1202 	error = smbfslookup(dvp, nm, vpp, cr, 1, ct);
1203 
1204 	smbfs_rw_exit(&dnp->r_rwlock);
1205 
1206 out:
1207 	return (error);
1208 }
1209 
1210 /* ARGSUSED */
1211 static int
1212 smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, int dnlc,
1213 	caller_context_t *ct)
1214 {
1215 	int		error;
1216 	int		supplen; /* supported length */
1217 	vnode_t		*vp;
1218 	smbnode_t	*dnp;
1219 	smbmntinfo_t	*smi;
1220 	/* struct smb_vc	*vcp; */
1221 	const char	*name = (const char *)nm;
1222 	int 		nmlen = strlen(nm);
1223 	int 		rplen;
1224 	struct smb_cred scred;
1225 	struct smbfattr fa;
1226 
1227 	smi = VTOSMI(dvp);
1228 	dnp = VTOSMB(dvp);
1229 
1230 	ASSERT(curproc->p_zone == smi->smi_zone);
1231 
1232 #ifdef NOT_YET
1233 	vcp = SSTOVC(smi->smi_share);
1234 
1235 	/* XXX: Should compute this once and store it in smbmntinfo_t */
1236 	supplen = (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) ? 255 : 12;
1237 #else
1238 	supplen = 255;
1239 #endif
1240 
1241 	/*
1242 	 * RWlock must be held, either reader or writer.
1243 	 * XXX: Can we check without looking directly
1244 	 * inside the struct smbfs_rwlock_t?
1245 	 */
1246 	ASSERT(dnp->r_rwlock.count != 0);
1247 
1248 	/*
1249 	 * If lookup is for "", just return dvp.  Don't need
1250 	 * to send it over the wire, look it up in the dnlc,
1251 	 * or perform any access checks.
1252 	 */
1253 	if (nmlen == 0) {
1254 		VN_HOLD(dvp);
1255 		*vpp = dvp;
1256 		return (0);
1257 	}
1258 
1259 	/* if the name is longer that what is supported, return an error */
1260 	if (nmlen > supplen)
1261 		return (ENAMETOOLONG);
1262 
1263 	/*
1264 	 * Avoid surprises with characters that are
1265 	 * illegal in Windows file names.
1266 	 * Todo: CATIA mappings  XXX
1267 	 */
1268 	if (strpbrk(nm, illegal_chars))
1269 		return (EINVAL);
1270 
1271 	/* if the dvp is not a directory, return an error */
1272 	if (dvp->v_type != VDIR)
1273 		return (ENOTDIR);
1274 
1275 	/* Need search permission in the directory. */
1276 	error = smbfs_access(dvp, VEXEC, 0, cr, ct);
1277 	if (error)
1278 		return (error);
1279 
1280 	/*
1281 	 * If lookup is for ".", just return dvp.  Don't need
1282 	 * to send it over the wire or look it up in the dnlc,
1283 	 * just need to check access (done above).
1284 	 */
1285 	if (nmlen == 1 && name[0] == '.') {
1286 		VN_HOLD(dvp);
1287 		*vpp = dvp;
1288 		return (0);
1289 	}
1290 
1291 #ifdef NOT_YET
1292 	if (dnlc) {
1293 	/*
1294 	 * NOTE: search the dnlc here
1295 	 */
1296 	}
1297 #endif
1298 
1299 	/*
1300 	 * Handle lookup of ".." which is quite tricky,
1301 	 * because the protocol gives us little help.
1302 	 *
1303 	 * We keep full pathnames (as seen on the server)
1304 	 * so we can just trim off the last component to
1305 	 * get the full pathname of the parent.  Note:
1306 	 * We don't actually copy and modify, but just
1307 	 * compute the trimmed length and pass that with
1308 	 * the current dir path (not null terminated).
1309 	 *
1310 	 * We don't go over-the-wire to get attributes
1311 	 * for ".." because we know it's a directory,
1312 	 * and we can just leave the rest "stale"
1313 	 * until someone does a getattr.
1314 	 */
1315 	if (nmlen == 2 && name[0] == '.' && name[1] == '.') {
1316 		if (dvp->v_flag & VROOT) {
1317 			/*
1318 			 * Already at the root.  This can happen
1319 			 * with directory listings at the root,
1320 			 * which lookup "." and ".." to get the
1321 			 * inode numbers.  Let ".." be the same
1322 			 * as "." in the FS root.
1323 			 */
1324 			VN_HOLD(dvp);
1325 			*vpp = dvp;
1326 			return (0);
1327 		}
1328 
1329 		/*
1330 		 * Find the parent path length.
1331 		 */
1332 		rplen = dnp->n_rplen;
1333 		ASSERT(rplen > 0);
1334 		while (--rplen >= 0) {
1335 			if (dnp->n_rpath[rplen] == '\\')
1336 				break;
1337 		}
1338 		if (rplen == 0) {
1339 			/* Found our way to the root. */
1340 			vp = SMBTOV(smi->smi_root);
1341 			VN_HOLD(vp);
1342 			*vpp = vp;
1343 			return (0);
1344 		}
1345 		vp = smbfs_make_node(dvp->v_vfsp,
1346 		    dnp->n_rpath, rplen,
1347 		    NULL, 0, NULL);
1348 		if (vp == NULL) {
1349 			return (ENOENT);
1350 		}
1351 		vp->v_type = VDIR;
1352 
1353 		/* Success! */
1354 		*vpp = vp;
1355 		return (0);
1356 	}
1357 
1358 	/*
1359 	 * Normal lookup of a child node.
1360 	 * Note we handled "." and ".." above.
1361 	 *
1362 	 * First, go over-the-wire to get the
1363 	 * node type (and attributes).
1364 	 */
1365 	smb_credinit(&scred, curproc, cr);
1366 	/* Note: this can allocate a new "name" */
1367 	error = smbfs_smb_lookup(dnp, &name, &nmlen, &fa, &scred);
1368 	smb_credrele(&scred);
1369 	if (error)
1370 		goto out;
1371 
1372 	/*
1373 	 * Find or create the node.
1374 	 */
1375 	error = smbfs_nget(dvp, name, nmlen, &fa, &vp);
1376 	if (error)
1377 		goto out;
1378 
1379 	/* Success! */
1380 	*vpp = vp;
1381 
1382 out:
1383 	/* smbfs_smb_lookup may have allocated name. */
1384 	if (name != nm)
1385 		smbfs_name_free(name, nmlen);
1386 
1387 	return (error);
1388 }
1389 
1390 /*
1391  * XXX
1392  * vsecattr_t is new to build 77, and we need to eventually support
1393  * it in order to create an ACL when an object is created.
1394  *
1395  * This op should support the new FIGNORECASE flag for case-insensitive
1396  * lookups, per PSARC 2007/244.
1397  */
1398 /* ARGSUSED */
1399 static int
1400 smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive,
1401 	int mode, vnode_t **vpp, cred_t *cr, int lfaware, caller_context_t *ct,
1402 	vsecattr_t *vsecp)
1403 {
1404 	int		error;
1405 	int		cerror;
1406 	vfs_t		*vfsp;
1407 	vnode_t		*vp;
1408 #ifdef NOT_YET
1409 	smbnode_t	*np;
1410 #endif
1411 	smbnode_t	*dnp;
1412 	smbmntinfo_t	*smi;
1413 	struct vattr	vattr;
1414 	struct smbfattr	fattr;
1415 	struct smb_cred	scred;
1416 	const char *name = (const char *)nm;
1417 	int		nmlen = strlen(nm);
1418 	uint32_t	disp;
1419 	uint16_t	fid;
1420 
1421 	vfsp = dvp->v_vfsp;
1422 	smi = VFTOSMI(vfsp);
1423 	dnp = VTOSMB(dvp);
1424 	vp = NULL;
1425 
1426 	if (curproc->p_zone != smi->smi_zone)
1427 		return (EPERM);
1428 
1429 	if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
1430 		return (EIO);
1431 
1432 	/*
1433 	 * Note: this may break mknod(2) calls to create a directory,
1434 	 * but that's obscure use.  Some other filesystems do this.
1435 	 * XXX: Later, redirect VDIR type here to _mkdir.
1436 	 */
1437 	if (va->va_type != VREG)
1438 		return (EINVAL);
1439 
1440 	/*
1441 	 * If the pathname is "", just use dvp, no checks.
1442 	 * Do this outside of the rwlock (like zfs).
1443 	 */
1444 	if (nmlen == 0) {
1445 		VN_HOLD(dvp);
1446 		*vpp = dvp;
1447 		return (0);
1448 	}
1449 
1450 	/* Don't allow "." or ".." through here. */
1451 	if ((nmlen == 1 && name[0] == '.') ||
1452 	    (nmlen == 2 && name[0] == '.' && name[1] == '.'))
1453 		return (EISDIR);
1454 
1455 	/*
1456 	 * We make a copy of the attributes because the caller does not
1457 	 * expect us to change what va points to.
1458 	 */
1459 	vattr = *va;
1460 
1461 	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
1462 		return (EINTR);
1463 	smb_credinit(&scred, curproc, cr);
1464 
1465 	/*
1466 	 * XXX: Do we need r_lkserlock too?
1467 	 * No use of any shared fid or fctx...
1468 	 */
1469 
1470 	/*
1471 	 * NFS needs to go over the wire, just to be sure whether the
1472 	 * file exists or not.  Using the DNLC can be dangerous in
1473 	 * this case when making a decision regarding existence.
1474 	 *
1475 	 * The SMB protocol does NOT really need to go OTW here
1476 	 * thanks to the expressive NTCREATE disposition values.
1477 	 * Unfortunately, to do Unix access checks correctly,
1478 	 * we need to know if the object already exists.
1479 	 * When the object does not exist, we need VWRITE on
1480 	 * the directory.  Note: smbfslookup() checks VEXEC.
1481 	 */
1482 	error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
1483 	if (error == 0) {
1484 		/*
1485 		 * file already exists
1486 		 */
1487 		if (exclusive == EXCL) {
1488 			error = EEXIST;
1489 			goto out;
1490 		}
1491 		/*
1492 		 * Verify requested access.
1493 		 */
1494 		error = smbfs_access(vp, mode, 0, cr, ct);
1495 		if (error)
1496 			goto out;
1497 
1498 		/*
1499 		 * Truncate (if requested).
1500 		 */
1501 		if ((vattr.va_mask & AT_SIZE) && vattr.va_size == 0) {
1502 			vattr.va_mask = AT_SIZE;
1503 			error = smbfssetattr(vp, &vattr, 0, cr);
1504 			if (error)
1505 				goto out;
1506 		}
1507 		/* Success! */
1508 #ifdef NOT_YET
1509 		vnevent_create(vp, ct);
1510 #endif
1511 		*vpp = vp;
1512 		goto out;
1513 	}
1514 
1515 	/*
1516 	 * The file did not exist.  Need VWRITE in the directory.
1517 	 */
1518 	error = smbfs_access(dvp, VWRITE, 0, cr, ct);
1519 	if (error)
1520 		goto out;
1521 
1522 	/*
1523 	 * Now things get tricky.  We also need to check the
1524 	 * requested open mode against the file we may create.
1525 	 * See comments at smbfs_access_rwx
1526 	 */
1527 	error = smbfs_access_rwx(vfsp, VREG, mode, cr);
1528 	if (error)
1529 		goto out;
1530 
1531 #ifdef NOT_YET
1532 	/* remove the entry from the negative entry from the dnlc */
1533 	dnlc_remove(dvp, name);
1534 #endif
1535 
1536 	/*
1537 	 * Now the code derived from Darwin,
1538 	 * but with greater use of NT_CREATE
1539 	 * disposition options.  Much changed.
1540 	 *
1541 	 * Create (or open) a new child node.
1542 	 * Note we handled "." and ".." above.
1543 	 */
1544 
1545 	if (exclusive == EXCL)
1546 		disp = NTCREATEX_DISP_CREATE;
1547 	else {
1548 		/* Truncate regular files if requested. */
1549 		if ((va->va_type == VREG) &&
1550 		    (va->va_mask & AT_SIZE) &&
1551 		    (va->va_size == 0))
1552 			disp = NTCREATEX_DISP_OVERWRITE_IF;
1553 		else
1554 			disp = NTCREATEX_DISP_OPEN_IF;
1555 	}
1556 	error = smbfs_smb_create(dnp, name, nmlen, &scred, &fid, disp, 0);
1557 	if (error)
1558 		goto out;
1559 
1560 	/*
1561 	 * XXX: Missing some code here to deal with
1562 	 * the case where we opened an existing file,
1563 	 * it's size is larger than 32-bits, and we're
1564 	 * setting the size from a process that's not
1565 	 * aware of large file offsets.  i.e.
1566 	 * from the NFS3 code:
1567 	 */
1568 #if NOT_YET /* XXX */
1569 	if ((vattr.va_mask & AT_SIZE) &&
1570 	    vp->v_type == VREG) {
1571 		np = VTOSMB(vp);
1572 		/*
1573 		 * Check here for large file handled
1574 		 * by LF-unaware process (as
1575 		 * ufs_create() does)
1576 		 */
1577 		if (!(lfaware & FOFFMAX)) {
1578 			mutex_enter(&np->r_statelock);
1579 			if (np->r_size > MAXOFF32_T)
1580 				error = EOVERFLOW;
1581 			mutex_exit(&np->r_statelock);
1582 		}
1583 		if (!error) {
1584 			vattr.va_mask = AT_SIZE;
1585 			error = smbfssetattr(vp,
1586 			    &vattr, 0, cr);
1587 		}
1588 	}
1589 #endif /* XXX */
1590 	/*
1591 	 * Should use the fid to get/set the size
1592 	 * while we have it opened here.  See above.
1593 	 */
1594 
1595 	cerror = smbfs_smb_close(smi->smi_share, fid, NULL, &scred);
1596 	if (cerror)
1597 		SMBERROR("error %d closing %s\\%s\n",
1598 		    cerror, dnp->n_rpath, name);
1599 
1600 	/*
1601 	 * In the open case, the name may differ a little
1602 	 * from what we passed to create (case, etc.)
1603 	 * so call lookup to get the (opened) name.
1604 	 *
1605 	 * XXX: Could avoid this extra lookup if the
1606 	 * "createact" result from NT_CREATE says we
1607 	 * created the object.
1608 	 */
1609 	error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred);
1610 	if (error)
1611 		goto out;
1612 
1613 	/* update attr and directory cache */
1614 	smbfs_attr_touchdir(dnp);
1615 
1616 	error = smbfs_nget(dvp, name, nmlen, &fattr, &vp);
1617 	if (error)
1618 		goto out;
1619 
1620 #ifdef NOT_YET
1621 	dnlc_update(dvp, name, vp);
1622 	/* XXX invalidate pages if we truncated? */
1623 #endif
1624 
1625 	/* Success! */
1626 	*vpp = vp;
1627 	error = 0;
1628 
1629 out:
1630 	smb_credrele(&scred);
1631 	if (name != nm)
1632 		smbfs_name_free(name, nmlen);
1633 	smbfs_rw_exit(&dnp->r_rwlock);
1634 	return (error);
1635 }
1636 
1637 /*
1638  * XXX
1639  * This op should support the new FIGNORECASE flag for case-insensitive
1640  * lookups, per PSARC 2007/244.
1641  */
1642 /* ARGSUSED */
1643 static int
1644 smbfs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct,
1645 	int flags)
1646 {
1647 	int		error;
1648 	vnode_t		*vp;
1649 	smbnode_t	*np;
1650 	smbnode_t	*dnp;
1651 	struct smb_cred	scred;
1652 	/* enum smbfsstat status; */
1653 	smbmntinfo_t	*smi;
1654 
1655 	smi = VTOSMI(dvp);
1656 
1657 	if (curproc->p_zone != smi->smi_zone)
1658 		return (EPERM);
1659 
1660 	if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
1661 		return (EIO);
1662 
1663 	dnp = VTOSMB(dvp);
1664 	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
1665 		return (EINTR);
1666 
1667 	/*
1668 	 * Verify access to the dirctory.
1669 	 */
1670 	error = smbfs_access(dvp, VWRITE|VEXEC, 0, cr, ct);
1671 	if (error)
1672 		goto out;
1673 
1674 	/*
1675 	 * NOTE:  the darwin code gets the "vp" passed in so it looks
1676 	 * like the "vp" has probably been "lookup"ed by the VFS layer.
1677 	 * It looks like we will need to lookup the vp to check the
1678 	 * caches and check if the object being deleted is a directory.
1679 	 */
1680 	error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
1681 	if (error)
1682 		goto out;
1683 
1684 	/* Never allow link/unlink directories on CIFS. */
1685 	if (vp->v_type == VDIR) {
1686 		VN_RELE(vp);
1687 		error = EPERM;
1688 		goto out;
1689 	}
1690 
1691 #ifdef NOT_YET
1692 	/*
1693 	 * First just remove the entry from the name cache, as it
1694 	 * is most likely the only entry for this vp.
1695 	 */
1696 	dnlc_remove(dvp, nm);
1697 
1698 	/*
1699 	 * If the file has a v_count > 1 then there may be more than one
1700 	 * entry in the name cache due multiple links or an open file,
1701 	 * but we don't have the real reference count so flush all
1702 	 * possible entries.
1703 	 */
1704 	if (vp->v_count > 1)
1705 		dnlc_purge_vp(vp);
1706 #endif /* NOT_YET */
1707 
1708 	/*
1709 	 * Now we have the real reference count on the vnode
1710 	 */
1711 	np = VTOSMB(vp);
1712 	mutex_enter(&np->r_statelock);
1713 	if (vp->v_count > 1) {
1714 		/*
1715 		 * NFS does a rename on remove here.
1716 		 * Probably not applicable for SMB.
1717 		 * Like Darwin, just return EBUSY.
1718 		 *
1719 		 * XXX: Todo - Ask the server to set the
1720 		 * set the delete-on-close flag.
1721 		 */
1722 		mutex_exit(&np->r_statelock);
1723 		error = EBUSY;
1724 		goto out;
1725 	} else {
1726 		mutex_exit(&np->r_statelock);
1727 
1728 		smb_credinit(&scred, curproc, cr);
1729 		error = smbfs_smb_delete(np, &scred, NULL, 0, 0);
1730 		smb_credrele(&scred);
1731 
1732 	}
1733 
1734 	VN_RELE(vp);
1735 
1736 out:
1737 	smbfs_rw_exit(&dnp->r_rwlock);
1738 
1739 	return (error);
1740 }
1741 
1742 
1743 /*
1744  * XXX
1745  * This op should support the new FIGNORECASE flag for case-insensitive
1746  * lookups, per PSARC 2007/244.
1747  */
1748 /* ARGSUSED */
1749 static int
1750 smbfs_rename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
1751 	caller_context_t *ct, int flags)
1752 {
1753 	/* vnode_t		*realvp; */
1754 
1755 	if (curproc->p_zone != VTOSMI(odvp)->smi_zone ||
1756 	    curproc->p_zone != VTOSMI(ndvp)->smi_zone)
1757 		return (EPERM);
1758 
1759 	if (VTOSMI(odvp)->smi_flags & SMI_DEAD ||
1760 	    VTOSMI(ndvp)->smi_flags & SMI_DEAD ||
1761 	    odvp->v_vfsp->vfs_flag & VFS_UNMOUNTED ||
1762 	    ndvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
1763 		return (EIO);
1764 
1765 	return (smbfsrename(odvp, onm, ndvp, nnm, cr, ct));
1766 }
1767 
1768 /*
1769  * smbfsrename does the real work of renaming in SMBFS
1770  */
1771 /* ARGSUSED */
1772 static int
1773 smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr,
1774 	caller_context_t *ct)
1775 {
1776 	int		error;
1777 	int		nvp_locked = 0;
1778 	vnode_t		*nvp = NULL;
1779 	vnode_t		*ovp = NULL;
1780 	smbnode_t	*onp;
1781 	smbnode_t	*odnp;
1782 	smbnode_t	*ndnp;
1783 	struct smb_cred	scred;
1784 	/* enum smbfsstat	status; */
1785 
1786 	ASSERT(curproc->p_zone == VTOSMI(odvp)->smi_zone);
1787 
1788 	if (strcmp(onm, ".") == 0 || strcmp(onm, "..") == 0 ||
1789 	    strcmp(nnm, ".") == 0 || strcmp(nnm, "..") == 0)
1790 		return (EINVAL);
1791 
1792 	/*
1793 	 * Check that everything is on the same filesystem.
1794 	 * vn_rename checks the fsid's, but in case we don't
1795 	 * fill those in correctly, check here too.
1796 	 */
1797 	if (odvp->v_vfsp != ndvp->v_vfsp)
1798 		return (EXDEV);
1799 
1800 	odnp = VTOSMB(odvp);
1801 	ndnp = VTOSMB(ndvp);
1802 
1803 	/*
1804 	 * Avoid deadlock here on old vs new directory nodes
1805 	 * by always taking the locks in order of address.
1806 	 * The order is arbitrary, but must be consistent.
1807 	 */
1808 	if (odnp < ndnp) {
1809 		if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER,
1810 		    SMBINTR(odvp)))
1811 			return (EINTR);
1812 		if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER,
1813 		    SMBINTR(ndvp))) {
1814 			smbfs_rw_exit(&odnp->r_rwlock);
1815 			return (EINTR);
1816 		}
1817 	} else {
1818 		if (smbfs_rw_enter_sig(&ndnp->r_rwlock, RW_WRITER,
1819 		    SMBINTR(ndvp)))
1820 			return (EINTR);
1821 		if (smbfs_rw_enter_sig(&odnp->r_rwlock, RW_WRITER,
1822 		    SMBINTR(odvp))) {
1823 			smbfs_rw_exit(&ndnp->r_rwlock);
1824 			return (EINTR);
1825 		}
1826 	}
1827 	/*
1828 	 * No returns after this point (goto out)
1829 	 */
1830 
1831 	/*
1832 	 * Need write access on source and target.
1833 	 * Server takes care of most checks.
1834 	 */
1835 	error = smbfs_access(odvp, VWRITE|VEXEC, 0, cr, ct);
1836 	if (error)
1837 		goto out;
1838 	if (odvp != ndvp) {
1839 		error = smbfs_access(ndvp, VWRITE, 0, cr, ct);
1840 		if (error)
1841 			goto out;
1842 	}
1843 
1844 	/*
1845 	 * Lookup the source name.  Must already exist.
1846 	 */
1847 	error = smbfslookup(odvp, onm, &ovp, cr, 0, ct);
1848 	if (error)
1849 		goto out;
1850 
1851 	/*
1852 	 * Lookup the target file.  If it exists, it needs to be
1853 	 * checked to see whether it is a mount point and whether
1854 	 * it is active (open).
1855 	 */
1856 	error = smbfslookup(ndvp, nnm, &nvp, cr, 0, ct);
1857 	if (!error) {
1858 		/*
1859 		 * Target (nvp) already exists.  Check that it
1860 		 * has the same type as the source.  The server
1861 		 * will check this also, (and more reliably) but
1862 		 * this lets us return the correct error codes.
1863 		 */
1864 		if (ovp->v_type == VDIR) {
1865 			if (nvp->v_type != VDIR) {
1866 				error = ENOTDIR;
1867 				goto out;
1868 			}
1869 		} else {
1870 			if (nvp->v_type == VDIR) {
1871 				error = EISDIR;
1872 				goto out;
1873 			}
1874 		}
1875 
1876 		/*
1877 		 * POSIX dictates that when the source and target
1878 		 * entries refer to the same file object, rename
1879 		 * must do nothing and exit without error.
1880 		 */
1881 		if (ovp == nvp) {
1882 			error = 0;
1883 			goto out;
1884 		}
1885 
1886 		/*
1887 		 * Also must ensure the target is not a mount point,
1888 		 * and keep mount/umount away until we're done.
1889 		 */
1890 		if (vn_vfsrlock(nvp)) {
1891 			error = EBUSY;
1892 			goto out;
1893 		}
1894 		nvp_locked = 1;
1895 		if (vn_mountedvfs(nvp) != NULL) {
1896 			error = EBUSY;
1897 			goto out;
1898 		}
1899 
1900 #ifdef NOT_YET
1901 		/*
1902 		 * Purge the name cache of all references to this vnode
1903 		 * so that we can check the reference count to infer
1904 		 * whether it is active or not.
1905 		 */
1906 		/*
1907 		 * First just remove the entry from the name cache, as it
1908 		 * is most likely the only entry for this vp.
1909 		 */
1910 		dnlc_remove(ndvp, nnm);
1911 		/*
1912 		 * If the file has a v_count > 1 then there may be more
1913 		 * than one entry in the name cache due multiple links
1914 		 * or an open file, but we don't have the real reference
1915 		 * count so flush all possible entries.
1916 		 */
1917 		if (nvp->v_count > 1)
1918 			dnlc_purge_vp(nvp);
1919 #endif
1920 
1921 		if (nvp->v_count > 1 && nvp->v_type != VDIR) {
1922 			/*
1923 			 * The target file exists, is not the same as
1924 			 * the source file, and is active.  Other FS
1925 			 * implementations unlink the target here.
1926 			 * For SMB, we don't assume we can remove an
1927 			 * open file.  Return an error instead.
1928 			 * Darwin returned an error here too.
1929 			 */
1930 			error = EEXIST;
1931 			goto out;
1932 		}
1933 	} /* nvp */
1934 
1935 #ifdef NOT_YET
1936 	dnlc_remove(odvp, onm);
1937 	dnlc_remove(ndvp, nnm);
1938 #endif
1939 
1940 	onp = VTOSMB(ovp);
1941 	smb_credinit(&scred, curproc, cr);
1942 	error = smbfs_smb_rename(onp, ndnp, nnm, strlen(nnm), &scred);
1943 	smb_credrele(&scred);
1944 
1945 
1946 out:
1947 	if (nvp) {
1948 		if (nvp_locked)
1949 			vn_vfsunlock(nvp);
1950 		VN_RELE(nvp);
1951 	}
1952 	if (ovp)
1953 		VN_RELE(ovp);
1954 
1955 	smbfs_rw_exit(&odnp->r_rwlock);
1956 	smbfs_rw_exit(&ndnp->r_rwlock);
1957 
1958 	return (error);
1959 }
1960 
1961 /*
1962  * XXX
1963  * vsecattr_t is new to build 77, and we need to eventually support
1964  * it in order to create an ACL when an object is created.
1965  *
1966  * This op should support the new FIGNORECASE flag for case-insensitive
1967  * lookups, per PSARC 2007/244.
1968  */
1969 /* ARGSUSED */
1970 static int
1971 smbfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp,
1972 	cred_t *cr, caller_context_t *ct, int flags, vsecattr_t *vsecp)
1973 {
1974 	vnode_t		*vp;
1975 	struct smbnode	*dnp = VTOSMB(dvp);
1976 	struct smbmntinfo *smi = VTOSMI(dvp);
1977 	struct smb_cred	scred;
1978 	struct smbfattr	fattr;
1979 	const char		*name = (const char *) nm;
1980 	int		nmlen = strlen(name);
1981 	int		error, hiderr;
1982 
1983 	if (curproc->p_zone != smi->smi_zone)
1984 		return (EPERM);
1985 
1986 	if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
1987 		return (EIO);
1988 
1989 	if ((nmlen == 1 && name[0] == '.') ||
1990 	    (nmlen == 2 && name[0] == '.' && name[1] == '.'))
1991 		return (EEXIST);
1992 
1993 	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
1994 		return (EINTR);
1995 	smb_credinit(&scred, curproc, cr);
1996 
1997 	/*
1998 	 * XXX: Do we need r_lkserlock too?
1999 	 * No use of any shared fid or fctx...
2000 	 */
2001 
2002 	/*
2003 	 * Require write access in the containing directory.
2004 	 */
2005 	error = smbfs_access(dvp, VWRITE, 0, cr, ct);
2006 	if (error)
2007 		goto out;
2008 
2009 	error = smbfs_smb_mkdir(dnp, name, nmlen, &scred);
2010 	if (error)
2011 		goto out;
2012 
2013 	error = smbfs_smb_lookup(dnp, &name, &nmlen, &fattr, &scred);
2014 	if (error)
2015 		goto out;
2016 
2017 	smbfs_attr_touchdir(dnp);
2018 
2019 	error = smbfs_nget(dvp, name, nmlen, &fattr, &vp);
2020 	if (error)
2021 		goto out;
2022 
2023 #ifdef NOT_YET
2024 	dnlc_update(dvp, name, vp);
2025 #endif
2026 
2027 	if (name[0] == '.')
2028 		if ((hiderr = smbfs_smb_hideit(VTOSMB(vp), NULL, 0, &scred)))
2029 			SMBVDEBUG("hide failure %d\n", hiderr);
2030 
2031 	/* Success! */
2032 	*vpp = vp;
2033 	error = 0;
2034 out:
2035 	smb_credrele(&scred);
2036 	smbfs_rw_exit(&dnp->r_rwlock);
2037 
2038 	if (name != nm)
2039 		smbfs_name_free(name, nmlen);
2040 
2041 	return (error);
2042 }
2043 
2044 /*
2045  * XXX
2046  * This op should support the new FIGNORECASE flag for case-insensitive
2047  * lookups, per PSARC 2007/244.
2048  */
2049 /* ARGSUSED */
2050 static int
2051 smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr,
2052 	caller_context_t *ct, int flags)
2053 {
2054 	vnode_t		*vp = NULL;
2055 	int		vp_locked = 0;
2056 	struct smbmntinfo *smi = VTOSMI(dvp);
2057 	struct smbnode	*dnp = VTOSMB(dvp);
2058 	struct smbnode	*np;
2059 	struct smb_cred	scred;
2060 	int		error;
2061 
2062 	if (curproc->p_zone != smi->smi_zone)
2063 		return (EPERM);
2064 
2065 	if (smi->smi_flags & SMI_DEAD || dvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2066 		return (EIO);
2067 
2068 	if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp)))
2069 		return (EINTR);
2070 	smb_credinit(&scred, curproc, cr);
2071 
2072 	/*
2073 	 * Require w/x access in the containing directory.
2074 	 * Server handles all other access checks.
2075 	 */
2076 	error = smbfs_access(dvp, VEXEC|VWRITE, 0, cr, ct);
2077 	if (error)
2078 		goto out;
2079 
2080 	/*
2081 	 * First lookup the entry to be removed.
2082 	 */
2083 	error = smbfslookup(dvp, nm, &vp, cr, 0, ct);
2084 	if (error)
2085 		goto out;
2086 	np = VTOSMB(vp);
2087 
2088 	/*
2089 	 * Disallow rmdir of "." or current dir, or the FS root.
2090 	 * Also make sure it's a directory, not a mount point,
2091 	 * and lock to keep mount/umount away until we're done.
2092 	 */
2093 	if ((vp == dvp) || (vp == cdir) || (vp->v_flag & VROOT)) {
2094 		error = EINVAL;
2095 		goto out;
2096 	}
2097 	if (vp->v_type != VDIR) {
2098 		error = ENOTDIR;
2099 		goto out;
2100 	}
2101 	if (vn_vfsrlock(vp)) {
2102 		error = EBUSY;
2103 		goto out;
2104 	}
2105 	vp_locked = 1;
2106 	if (vn_mountedvfs(vp) != NULL) {
2107 		error = EBUSY;
2108 		goto out;
2109 	}
2110 
2111 	error = smbfs_smb_rmdir(np, &scred);
2112 	if (error)
2113 		goto out;
2114 
2115 	mutex_enter(&np->r_statelock);
2116 	dnp->n_flag |= NMODIFIED;
2117 	mutex_exit(&np->r_statelock);
2118 	smbfs_attr_touchdir(dnp);
2119 #ifdef NOT_YET
2120 	dnlc_remove(dvp, nm);
2121 	dnlc_purge_vp(vp);
2122 #endif
2123 	smb_rmhash(np);
2124 
2125 out:
2126 	if (vp) {
2127 		if (vp_locked)
2128 			vn_vfsunlock(vp);
2129 		VN_RELE(vp);
2130 	}
2131 	smb_credrele(&scred);
2132 	smbfs_rw_exit(&dnp->r_rwlock);
2133 
2134 	return (error);
2135 }
2136 
2137 
2138 /* ARGSUSED */
2139 static int
2140 smbfs_readdir(vnode_t *vp, struct uio *uiop, cred_t *cr, int *eofp,
2141 	caller_context_t *ct, int flags)
2142 {
2143 	struct smbnode	*np = VTOSMB(vp);
2144 	int		error = 0;
2145 	smbmntinfo_t	*smi;
2146 
2147 	smi = VTOSMI(vp);
2148 
2149 	if (curproc->p_zone != smi->smi_zone)
2150 		return (EIO);
2151 
2152 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2153 		return (EIO);
2154 
2155 	/*
2156 	 * Require read access in the directory.
2157 	 */
2158 	error = smbfs_access(vp, VREAD, 0, cr, ct);
2159 	if (error)
2160 		return (error);
2161 
2162 	ASSERT(smbfs_rw_lock_held(&np->r_rwlock, RW_READER));
2163 
2164 	/*
2165 	 * XXX: Todo readdir cache here
2166 	 * Note: NFS code is just below this.
2167 	 *
2168 	 * I am serializing the entire readdir opreation
2169 	 * now since we have not yet implemented readdir
2170 	 * cache. This fix needs to be revisited once
2171 	 * we implement readdir cache.
2172 	 */
2173 	if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_WRITER, SMBINTR(vp)))
2174 		return (EINTR);
2175 
2176 	error = smbfs_readvdir(vp, uiop, cr, eofp, ct);
2177 
2178 	smbfs_rw_exit(&np->r_lkserlock);
2179 
2180 	return (error);
2181 }
2182 
2183 /* ARGSUSED */
2184 static int
2185 smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp,
2186 	caller_context_t *ct)
2187 {
2188 	size_t		dbufsiz;
2189 	struct dirent64 *dp;
2190 	struct smb_cred scred;
2191 	vnode_t		*newvp;
2192 	struct smbnode	*np = VTOSMB(vp);
2193 	int		nmlen, reclen, error = 0;
2194 	long		offset, limit;
2195 	struct smbfs_fctx *ctx;
2196 
2197 	ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone);
2198 
2199 	/* Make sure we serialize for n_dirseq use. */
2200 	ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_WRITER));
2201 
2202 	/* Min size is DIRENT64_RECLEN(256) rounded up. */
2203 	if (uio->uio_resid < 512 || uio->uio_offset < 0)
2204 		return (EINVAL);
2205 
2206 	/*
2207 	 * This dnlc_purge_vp ensures that name cache for this dir will be
2208 	 * current - it'll only have the items for which the smbfs_nget
2209 	 * MAKEENTRY happened.
2210 	 */
2211 #ifdef NOT_YET
2212 	if (smbfs_fastlookup)
2213 		dnlc_purge_vp(vp);
2214 #endif
2215 	SMBVDEBUG("dirname='%s'\n", np->n_rpath);
2216 	smb_credinit(&scred, curproc, cr);
2217 	dbufsiz = DIRENT64_RECLEN(MAXNAMELEN);
2218 	dp = kmem_alloc(dbufsiz, KM_SLEEP);
2219 
2220 	offset = uio->uio_offset; /* NB: "cookie" */
2221 	limit = uio->uio_resid / DIRENT64_RECLEN(1);
2222 	SMBVDEBUG("offset=0x%ld, limit=0x%ld\n", offset, limit);
2223 
2224 	if (offset == 0) {
2225 		/* Don't know EOF until findclose */
2226 		np->n_direof = -1;
2227 	} else if (offset == np->n_direof) {
2228 		/* Arrived at end of directory. */
2229 		goto out;
2230 	}
2231 
2232 	/*
2233 	 * Generate the "." and ".." entries here so we can
2234 	 * (1) make sure they appear (but only once), and
2235 	 * (2) deal with getting their I numbers which the
2236 	 * findnext below does only for normal names.
2237 	 */
2238 	while (limit && offset < 2) {
2239 		limit--;
2240 		reclen = DIRENT64_RECLEN(offset + 1);
2241 		bzero(dp, reclen);
2242 		/*LINTED*/
2243 		dp->d_reclen = reclen;
2244 		/* Tricky: offset 0 is ".", offset 1 is ".." */
2245 		dp->d_name[0] = '.';
2246 		dp->d_name[1] = '.';
2247 		dp->d_name[offset + 1] = '\0';
2248 		/*
2249 		 * Want the real I-numbers for the "." and ".."
2250 		 * entries.  For these two names, we know that
2251 		 * smbfslookup can do this all locally.
2252 		 */
2253 		error = smbfslookup(vp, dp->d_name, &newvp, cr, 1, ct);
2254 		if (error) {
2255 			dp->d_ino = np->n_ino + offset; /* fiction */
2256 		} else {
2257 			dp->d_ino = VTOSMB(newvp)->n_ino;
2258 			VN_RELE(newvp);
2259 		}
2260 		dp->d_off = offset + 1;  /* see d_off below */
2261 		error = uiomove(dp, dp->d_reclen, UIO_READ, uio);
2262 		if (error)
2263 			goto out;
2264 		uio->uio_offset = ++offset;
2265 	}
2266 	if (limit == 0)
2267 		goto out;
2268 	if (offset != np->n_dirofs || np->n_dirseq == NULL) {
2269 		SMBVDEBUG("Reopening search %ld:%ld\n", offset, np->n_dirofs);
2270 		if (np->n_dirseq) {
2271 			(void) smbfs_smb_findclose(np->n_dirseq, &scred);
2272 			np->n_dirseq = NULL;
2273 		}
2274 		np->n_dirofs = 2;
2275 		error = smbfs_smb_findopen(np, "*", 1,
2276 		    SMB_FA_SYSTEM | SMB_FA_HIDDEN | SMB_FA_DIR,
2277 		    &scred, &ctx);
2278 		if (error) {
2279 			SMBVDEBUG("can not open search, error = %d", error);
2280 			goto out;
2281 		}
2282 		np->n_dirseq = ctx;
2283 	} else
2284 		ctx = np->n_dirseq;
2285 	while (np->n_dirofs < offset) {
2286 		if (smbfs_smb_findnext(ctx, offset - np->n_dirofs++,
2287 		    &scred) != 0) {
2288 			(void) smbfs_smb_findclose(np->n_dirseq, &scred);
2289 			np->n_dirseq = NULL;
2290 			np->n_direof = np->n_dirofs;
2291 			np->n_dirofs = 0;
2292 			*eofp = 1;
2293 			error = 0;
2294 			goto out;
2295 		}
2296 	}
2297 	error = 0;
2298 	for (; limit; limit--) {
2299 		error = smbfs_smb_findnext(ctx, limit, &scred);
2300 		if (error) {
2301 			if (error == EBADRPC)
2302 				error = ENOENT;
2303 			(void) smbfs_smb_findclose(np->n_dirseq, &scred);
2304 			np->n_dirseq = NULL;
2305 			np->n_direof = np->n_dirofs;
2306 			np->n_dirofs = 0;
2307 			*eofp = 1;
2308 			error = 0;
2309 			break;
2310 		}
2311 		np->n_dirofs++;
2312 		/* Sanity check the name length. */
2313 		nmlen = ctx->f_nmlen;
2314 		if (nmlen > (MAXNAMELEN - 1)) {
2315 			nmlen = MAXNAMELEN - 1;
2316 			SMBVDEBUG("Truncating name: %s\n", ctx->f_name);
2317 		}
2318 		reclen = DIRENT64_RECLEN(nmlen);
2319 		if (uio->uio_resid < reclen)
2320 			break;
2321 		bzero(dp, reclen);
2322 		/*LINTED*/
2323 		dp->d_reclen = reclen;
2324 		dp->d_ino = ctx->f_attr.fa_ino;
2325 		/*
2326 		 * Note: d_off is the offset that a user-level program
2327 		 * should seek to for reading the _next_ directory entry.
2328 		 * See libc: readdir, telldir, seekdir
2329 		 */
2330 		dp->d_off = offset + 1;
2331 		bcopy(ctx->f_name, dp->d_name, nmlen);
2332 		dp->d_name[nmlen] = '\0';
2333 #ifdef NOT_YET
2334 		if (smbfs_fastlookup) {
2335 			if (smbfs_nget(vp, ctx->f_name,
2336 			    ctx->f_nmlen, &ctx->f_attr, &newvp) == 0)
2337 				VN_RELE(newvp);
2338 		}
2339 #endif /* NOT_YET */
2340 		error = uiomove(dp, dp->d_reclen, UIO_READ, uio);
2341 		if (error)
2342 			break;
2343 		uio->uio_offset = ++offset;
2344 	}
2345 	if (error == ENOENT)
2346 		error = 0;
2347 out:
2348 	kmem_free(dp, dbufsiz);
2349 	smb_credrele(&scred);
2350 	return (error);
2351 }
2352 
2353 
2354 /*
2355  * The pair of functions VOP_RWLOCK, VOP_RWUNLOCK
2356  * are optional functions that are called by:
2357  *    getdents, before/after VOP_READDIR
2358  *    pread, before/after ... VOP_READ
2359  *    pwrite, before/after ... VOP_WRITE
2360  *    (other places)
2361  *
2362  * Careful here: None of the above check for any
2363  * error returns from VOP_RWLOCK / VOP_RWUNLOCK!
2364  * In fact, the return value from _rwlock is NOT
2365  * an error code, but V_WRITELOCK_TRUE / _FALSE.
2366  *
2367  * Therefore, it's up to _this_ code to make sure
2368  * the lock state remains balanced, which means
2369  * we can't "bail out" on interrupts, etc.
2370  */
2371 
2372 /* ARGSUSED2 */
2373 static int
2374 smbfs_rwlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
2375 {
2376 	smbnode_t	*np = VTOSMB(vp);
2377 
2378 	if (!write_lock) {
2379 		(void) smbfs_rw_enter_sig(&np->r_rwlock, RW_READER, FALSE);
2380 		return (V_WRITELOCK_FALSE);
2381 	}
2382 
2383 
2384 	(void) smbfs_rw_enter_sig(&np->r_rwlock, RW_WRITER, FALSE);
2385 	return (V_WRITELOCK_TRUE);
2386 }
2387 
2388 /* ARGSUSED */
2389 static void
2390 smbfs_rwunlock(vnode_t *vp, int write_lock, caller_context_t *ctp)
2391 {
2392 	smbnode_t	*np = VTOSMB(vp);
2393 
2394 	smbfs_rw_exit(&np->r_rwlock);
2395 }
2396 
2397 
2398 /* ARGSUSED */
2399 static int
2400 smbfs_seek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
2401 {
2402 	smbmntinfo_t	*smi;
2403 
2404 	smi = VTOSMI(vp);
2405 
2406 	if (curproc->p_zone != smi->smi_zone)
2407 		return (EPERM);
2408 
2409 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2410 		return (EIO);
2411 
2412 	/*
2413 	 * Because we stuff the readdir cookie into the offset field
2414 	 * someone may attempt to do an lseek with the cookie which
2415 	 * we want to succeed.
2416 	 */
2417 	if (vp->v_type == VDIR)
2418 		return (0);
2419 
2420 	/* Like NFS3, just check for 63-bit overflow. */
2421 	if (*noffp < 0)
2422 		return (EINVAL);
2423 
2424 	return (0);
2425 }
2426 
2427 
2428 /*
2429  * XXX
2430  * This op may need to support PSARC 2007/440, nbmand changes for CIFS Service.
2431  */
2432 static int
2433 smbfs_frlock(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
2434 	offset_t offset, struct flk_callback *flk_cbp, cred_t *cr,
2435 	caller_context_t *ct)
2436 {
2437 	if (curproc->p_zone != VTOSMI(vp)->smi_zone)
2438 		return (EIO);
2439 
2440 	if (VTOSMI(vp)->smi_flags & SMI_LLOCK)
2441 		return (fs_frlock(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
2442 	else
2443 		return (ENOSYS);
2444 }
2445 
2446 /*
2447  * Free storage space associated with the specified vnode.  The portion
2448  * to be freed is specified by bfp->l_start and bfp->l_len (already
2449  * normalized to a "whence" of 0).
2450  *
2451  * Called by fcntl(fd, F_FREESP, lkp) for libc:ftruncate, etc.
2452  */
2453 /* ARGSUSED */
2454 static int
2455 smbfs_space(vnode_t *vp, int cmd, struct flock64 *bfp, int flag,
2456 	offset_t offset, cred_t *cr, caller_context_t *ct)
2457 {
2458 	int		error;
2459 	smbmntinfo_t	*smi;
2460 
2461 	smi = VTOSMI(vp);
2462 
2463 	if (curproc->p_zone != smi->smi_zone)
2464 		return (EIO);
2465 
2466 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2467 		return (EIO);
2468 
2469 	ASSERT(vp->v_type == VREG);
2470 	if (cmd != F_FREESP)
2471 		return (EINVAL);
2472 
2473 	/*
2474 	 * Like NFS3, no 32-bit offset checks here.
2475 	 * Our SMB layer takes care to return EFBIG
2476 	 * when it has to fallback to a 32-bit call.
2477 	 */
2478 
2479 	error = convoff(vp, bfp, 0, offset);
2480 	if (!error) {
2481 		ASSERT(bfp->l_start >= 0);
2482 		if (bfp->l_len == 0) {
2483 			struct vattr va;
2484 
2485 			/*
2486 			 * ftruncate should not change the ctime and
2487 			 * mtime if we truncate the file to its
2488 			 * previous size.
2489 			 */
2490 			va.va_mask = AT_SIZE;
2491 			error = smbfsgetattr(vp, &va, cr);
2492 			if (error || va.va_size == bfp->l_start)
2493 				return (error);
2494 			va.va_mask = AT_SIZE;
2495 			va.va_size = bfp->l_start;
2496 			error = smbfssetattr(vp, &va, 0, cr);
2497 		} else
2498 			error = EINVAL;
2499 	}
2500 
2501 	return (error);
2502 }
2503 
2504 /* ARGSUSED */
2505 static int
2506 smbfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr,
2507 	caller_context_t *ct)
2508 {
2509 	smbmntinfo_t *smi;
2510 	struct smb_share *ssp;
2511 
2512 	smi = VTOSMI(vp);
2513 
2514 	if (curproc->p_zone != smi->smi_zone)
2515 		return (EIO);
2516 
2517 	if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED)
2518 		return (EIO);
2519 
2520 	switch (cmd) {
2521 	case _PC_FILESIZEBITS:
2522 		ssp = smi->smi_share;
2523 		if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)
2524 			*valp = 64;
2525 		else
2526 			*valp = 32;
2527 		break;
2528 
2529 	case _PC_LINK_MAX:
2530 		/* We only ever report one link to an object */
2531 		*valp = 1;
2532 		break;
2533 
2534 	case _PC_ACL_ENABLED:
2535 		/*
2536 		 * Always say "yes" here.  Our _getsecattr
2537 		 * will build a trivial ACL when needed,
2538 		 * i.e. when server does not have ACLs.
2539 		 */
2540 		*valp = _ACL_ACE_ENABLED;
2541 		break;
2542 
2543 	case _PC_SYMLINK_MAX:	/* No symlinks until we do Unix extensions */
2544 	case _PC_XATTR_EXISTS:	/* No xattrs yet */
2545 		*valp = 0;
2546 		break;
2547 
2548 	default:
2549 		return (fs_pathconf(vp, cmd, valp, cr, ct));
2550 	}
2551 	return (0);
2552 }
2553 
2554 /* ARGSUSED */
2555 static int
2556 smbfs_getsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr,
2557 	caller_context_t *ct)
2558 {
2559 	vfs_t *vfsp;
2560 	smbmntinfo_t *smi;
2561 	int	error, uid, gid;
2562 	uint_t	mask;
2563 
2564 	vfsp = vp->v_vfsp;
2565 	smi = VFTOSMI(vfsp);
2566 
2567 	if (curproc->p_zone != smi->smi_zone)
2568 		return (EIO);
2569 
2570 	if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
2571 		return (EIO);
2572 
2573 	/*
2574 	 * Our _pathconf indicates _ACL_ACE_ENABLED,
2575 	 * so we should only see VSA_ACE, etc here.
2576 	 * Note: vn_create asks for VSA_DFACLCNT,
2577 	 * and it expects ENOSYS and empty data.
2578 	 */
2579 	mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT |
2580 	    VSA_ACE_ACLFLAGS | VSA_ACE_ALLTYPES);
2581 	if (mask == 0)
2582 		return (ENOSYS);
2583 
2584 	/* XXX - access check ACE_READ_ACL? */
2585 
2586 	if (smi->smi_fsattr & FILE_PERSISTENT_ACLS) {
2587 		error = smbfs_getacl(vp, vsa, &uid, &gid, flag, cr);
2588 		/* XXX: Save uid/gid somewhere? */
2589 	} else
2590 		error = ENOSYS;
2591 
2592 	if (error == ENOSYS)
2593 		error = fs_fab_acl(vp, vsa, flag, cr, ct);
2594 
2595 	return (error);
2596 }
2597 
2598 /* ARGSUSED */
2599 static int
2600 smbfs_setsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr,
2601 	caller_context_t *ct)
2602 {
2603 	vfs_t *vfsp;
2604 	smbmntinfo_t *smi;
2605 	int	error;
2606 	uint_t	mask;
2607 
2608 	vfsp = vp->v_vfsp;
2609 	smi = VFTOSMI(vfsp);
2610 
2611 	if (curproc->p_zone != smi->smi_zone)
2612 		return (EIO);
2613 
2614 	if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED)
2615 		return (EIO);
2616 
2617 	/*
2618 	 * Our _pathconf indicates _ACL_ACE_ENABLED,
2619 	 * so we should only see VSA_ACE, etc here.
2620 	 */
2621 	mask = vsa->vsa_mask & (VSA_ACE | VSA_ACECNT);
2622 	if (mask == 0)
2623 		return (ENOSYS);
2624 
2625 	/*
2626 	 * If and when smbfs_access is extended, we can
2627 	 * check ACE_WRITE_ACL here instead.  (XXX todo)
2628 	 * For now, in-line parts of smbfs_access,
2629 	 * i.e. only allow _setacl by the owner,
2630 	 * and check for read-only FS.
2631 	 */
2632 	if (vfsp->vfs_flag & VFS_RDONLY)
2633 		return (EROFS);
2634 	if (crgetuid(cr) != smi->smi_args.uid)
2635 		return (EACCES);
2636 
2637 	if (smi->smi_fsattr & FILE_PERSISTENT_ACLS) {
2638 		error = smbfs_setacl(vp, vsa, -1, -1, flag, cr);
2639 	} else
2640 		error = ENOSYS;
2641 
2642 	return (error);
2643 }
2644 
2645 
2646 /*
2647  * XXX
2648  * This op should eventually support PSARC 2007/268.
2649  */
2650 static int
2651 smbfs_shrlock(vnode_t *vp, int cmd, struct shrlock *shr, int flag, cred_t *cr,
2652 	caller_context_t *ct)
2653 {
2654 	if (curproc->p_zone != VTOSMI(vp)->smi_zone)
2655 		return (EIO);
2656 
2657 	if (VTOSMI(vp)->smi_flags & SMI_LLOCK)
2658 		return (fs_shrlock(vp, cmd, shr, flag, cr, ct));
2659 	else
2660 		return (ENOSYS);
2661 }
2662