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