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