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