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