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