xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_vops.c (revision ca9327a6de44d69ddab3668cc1e143ce781387a3)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/uio.h>
31 #include <sys/statvfs.h>
32 #include <sys/vnode.h>
33 #include <sys/thread.h>
34 #include <sys/pathname.h>
35 #include <sys/cred.h>
36 #include <sys/extdirent.h>
37 #include <sys/nbmlock.h>
38 #include <sys/share.h>
39 #include <sys/fcntl.h>
40 #include <nfs/lm.h>
41 
42 #include <smbsrv/smb_vops.h>
43 #include <smbsrv/string.h>
44 
45 #include <smbsrv/smbtrans.h>
46 #include <smbsrv/smb_fsops.h>
47 #include <smbsrv/smb_kproto.h>
48 #include <smbsrv/smb_incl.h>
49 
50 void
51 smb_vop_setup_xvattr(smb_attr_t *smb_attr, xvattr_t *xvattr);
52 
53 static int
54 smb_vop_readdir_readpage(vnode_t *, void *, uint32_t, int *, cred_t *, int);
55 
56 static int
57 smb_vop_readdir_entry(vnode_t *, uint32_t *, char *, int *,
58     ino64_t *, vnode_t **, char *, int, cred_t *, char *, int);
59 
60 static int
61 smb_vop_getdents_entries(smb_node_t *, uint32_t *, int32_t *, char *, uint32_t,
62     smb_request_t *, cred_t *, char *, int *, int, char *);
63 
64 extern int
65 smb_gather_dents_info(char *args, ino_t fileid, int namelen,
66     char *name, uint32_t cookie, int32_t *countp,
67     smb_attr_t *attr, struct smb_node *snode,
68     char *shortname, char *name83);
69 
70 static void
71 smb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp);
72 
73 extern sysid_t lm_alloc_sysidt();
74 
75 #define	SMB_AT_MAX	16
76 static uint_t smb_attrmap[SMB_AT_MAX] = {
77 	0,
78 	AT_TYPE,
79 	AT_MODE,
80 	AT_UID,
81 	AT_GID,
82 	AT_FSID,
83 	AT_NODEID,
84 	AT_NLINK,
85 	AT_SIZE,
86 	AT_ATIME,
87 	AT_MTIME,
88 	AT_CTIME,
89 	AT_RDEV,
90 	AT_BLKSIZE,
91 	AT_NBLOCKS,
92 	AT_SEQ
93 };
94 
95 static boolean_t	smb_vop_initialized = B_FALSE;
96 caller_context_t	smb_ct;
97 
98 /*
99  * smb_vop_init
100  *
101  * This function is not multi-thread safe. The caller must make sure only one
102  * thread makes the call.
103  */
104 int
105 smb_vop_init(void)
106 {
107 	if (smb_vop_initialized)
108 		return (0);
109 	/*
110 	 * The caller_context will be used primarily for range locking.
111 	 * Since the CIFS server is mapping its locks to POSIX locks,
112 	 * only one pid is used for operations originating from the
113 	 * CIFS server (to represent CIFS in the VOP_FRLOCK routines).
114 	 */
115 	smb_ct.cc_sysid = lm_alloc_sysidt();
116 	if (smb_ct.cc_sysid == LM_NOSYSID)
117 		return (ENOMEM);
118 
119 	smb_ct.cc_caller_id = fs_new_caller_id();
120 	smb_ct.cc_pid = IGN_PID;
121 	smb_ct.cc_flags = 0;
122 
123 	smb_vop_initialized = B_TRUE;
124 	return (0);
125 }
126 
127 /*
128  * smb_vop_fini
129  *
130  * This function is not multi-thread safe. The caller must make sure only one
131  * thread makes the call.
132  */
133 void
134 smb_vop_fini(void)
135 {
136 	if (!smb_vop_initialized)
137 		return;
138 
139 	lm_free_sysidt(smb_ct.cc_sysid);
140 	smb_ct.cc_pid = IGN_PID;
141 	smb_ct.cc_sysid = LM_NOSYSID;
142 	smb_vop_initialized = B_FALSE;
143 }
144 
145 /*
146  * The smb_ct will be used primarily for range locking.
147  * Since the CIFS server is mapping its locks to POSIX locks,
148  * only one pid is used for operations originating from the
149  * CIFS server (to represent CIFS in the VOP_FRLOCK routines).
150  */
151 
152 int
153 smb_vop_open(vnode_t **vpp, int mode, cred_t *cred)
154 {
155 	return (VOP_OPEN(vpp, mode, cred, &smb_ct));
156 }
157 
158 int
159 smb_vop_close(vnode_t *vp, int mode, cred_t *cred)
160 {
161 	return (VOP_CLOSE(vp, mode, 1, (offset_t)0, cred, &smb_ct));
162 }
163 
164 /*
165  * The smb_vop_* functions have minimal knowledge of CIFS semantics and
166  * serve as an interface to the VFS layer.
167  *
168  * Only smb_fsop_* layer functions should call smb_vop_* layer functions.
169  * (Higher-level CIFS service code should never skip the smb_fsop_* layer
170  * to call smb_vop_* layer functions directly.)
171  */
172 
173 /*
174  * XXX - Extended attributes support in the file system assumed.
175  * This is needed for full NT Streams functionality.
176  */
177 
178 int
179 smb_vop_read(vnode_t *vp, uio_t *uiop, cred_t *cr)
180 {
181 	int error;
182 
183 	(void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
184 	error = VOP_READ(vp, uiop, 0, cr, &smb_ct);
185 	VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
186 	return (error);
187 }
188 
189 int
190 smb_vop_write(vnode_t *vp, uio_t *uiop, uint32_t *flag, uint32_t *lcount,
191     cred_t *cr)
192 {
193 	int error;
194 	int ioflag = 0;
195 
196 	*lcount = uiop->uio_resid;
197 
198 	if (*flag == FSSTAB_FILE_SYNC)
199 		ioflag = FSYNC;
200 
201 	uiop->uio_llimit = MAXOFFSET_T;
202 
203 	(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
204 	error = VOP_WRITE(vp, uiop, ioflag, cr, &smb_ct);
205 	VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
206 
207 	*lcount -= uiop->uio_resid;
208 
209 	return (error);
210 }
211 
212 /*
213  * smb_vop_getattr()
214  *
215  * smb_fsop_getattr()/smb_vop_getattr() should always be called from the CIFS
216  * service (instead of calling VOP_GETATTR directly) to retrieve attributes
217  * due to special processing needed for streams files.
218  *
219  * All attributes are retrieved.
220  *
221  * A named stream's attributes (as far as CIFS is concerned) are those of the
222  * unnamed (i.e. data) stream (minus the size attribute), and the size of the
223  * named stream.  Though the file system may store attributes other than size
224  * with the named stream, these should not be used by CIFS for any purpose.
225  *
226  * When vp denotes a named stream, then unnamed_vp should be passed in (denoting
227  * the corresponding unnamed stream).
228  */
229 
230 int
231 smb_vop_getattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *ret_attr,
232     int flags, cred_t *cr)
233 {
234 	int error;
235 	vnode_t *use_vp;
236 	smb_attr_t tmp_attr;
237 	xvattr_t tmp_xvattr;
238 	xoptattr_t *xoap = NULL;
239 
240 	if (unnamed_vp)
241 		use_vp = unnamed_vp;
242 	else
243 		use_vp = vp;
244 
245 	if (vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) {
246 		xva_init(&tmp_xvattr);
247 		xoap = xva_getxoptattr(&tmp_xvattr);
248 
249 		ASSERT(xoap);
250 
251 		smb_sa_to_va_mask(ret_attr->sa_mask,
252 		    &tmp_xvattr.xva_vattr.va_mask);
253 
254 		XVA_SET_REQ(&tmp_xvattr, XAT_READONLY);
255 		XVA_SET_REQ(&tmp_xvattr, XAT_HIDDEN);
256 		XVA_SET_REQ(&tmp_xvattr, XAT_SYSTEM);
257 		XVA_SET_REQ(&tmp_xvattr, XAT_ARCHIVE);
258 		XVA_SET_REQ(&tmp_xvattr, XAT_CREATETIME);
259 
260 		if ((error = VOP_GETATTR(use_vp, (vattr_t *)&tmp_xvattr, flags,
261 		    cr, &smb_ct)) != 0)
262 			return (error);
263 
264 		ret_attr->sa_vattr = tmp_xvattr.xva_vattr;
265 
266 		/*
267 		 * Copy special attributes to ret_attr parameter
268 		 */
269 
270 		ret_attr->sa_dosattr = 0;
271 
272 		ASSERT(tmp_xvattr.xva_vattr.va_mask & AT_XVATTR);
273 
274 		xoap = xva_getxoptattr(&tmp_xvattr);
275 		ASSERT(xoap);
276 
277 		if (XVA_ISSET_RTN(&tmp_xvattr, XAT_READONLY)) {
278 			if (xoap->xoa_readonly)
279 				ret_attr->sa_dosattr |= FILE_ATTRIBUTE_READONLY;
280 		}
281 
282 		if (XVA_ISSET_RTN(&tmp_xvattr, XAT_HIDDEN)) {
283 			if (xoap->xoa_hidden)
284 				ret_attr->sa_dosattr |= FILE_ATTRIBUTE_HIDDEN;
285 		}
286 
287 		if (XVA_ISSET_RTN(&tmp_xvattr, XAT_SYSTEM)) {
288 			if (xoap->xoa_system)
289 				ret_attr->sa_dosattr |= FILE_ATTRIBUTE_SYSTEM;
290 		}
291 
292 		if (XVA_ISSET_RTN(&tmp_xvattr, XAT_ARCHIVE)) {
293 			if (xoap->xoa_archive)
294 				ret_attr->sa_dosattr |= FILE_ATTRIBUTE_ARCHIVE;
295 		}
296 
297 		ret_attr->sa_crtime = xoap->xoa_createtime;
298 
299 		if (unnamed_vp && (ret_attr->sa_mask & SMB_AT_SIZE)) {
300 			/*
301 			 * Retrieve stream size attribute into temporary
302 			 * structure, in case the underlying file system
303 			 * returns attributes other than the size (we do not
304 			 * want to have ret_attr's other fields get
305 			 * overwritten).
306 			 *
307 			 * Note that vp is used here, and not use_vp.
308 			 * Also, only AT_SIZE is needed.
309 			 */
310 
311 			tmp_xvattr.xva_vattr.va_mask = AT_SIZE;
312 
313 			if ((error = VOP_GETATTR(vp, (vattr_t *)&tmp_xvattr,
314 			    flags, cr, &smb_ct)) != 0)
315 				return (error);
316 
317 			ret_attr->sa_vattr.va_size =
318 			    tmp_xvattr.xva_vattr.va_size;
319 
320 		}
321 
322 		if (ret_attr->sa_vattr.va_type == VDIR) {
323 			ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY;
324 		}
325 
326 		return (error);
327 	}
328 
329 	/*
330 	 * Support for file systems without VFSFT_XVATTR
331 	 */
332 
333 	smb_sa_to_va_mask(ret_attr->sa_mask,
334 	    &ret_attr->sa_vattr.va_mask);
335 
336 	error = VOP_GETATTR(use_vp, &ret_attr->sa_vattr, flags, cr, &smb_ct);
337 
338 	if (error != 0)
339 		return (error);
340 
341 	/*
342 	 * "Fake" DOS attributes and create time, filesystem doesn't support
343 	 * them.
344 	 */
345 
346 	ret_attr->sa_dosattr = 0;
347 	ret_attr->sa_crtime = ret_attr->sa_vattr.va_ctime;
348 
349 	if (unnamed_vp && (ret_attr->sa_mask & SMB_AT_SIZE)) {
350 		/*
351 		 * Retrieve stream size attribute into temporary structure,
352 		 * in case the underlying file system returns attributes
353 		 * other than the size (we do not want to have ret_attr's
354 		 * other fields get overwritten).
355 		 *
356 		 * Note that vp is used here, and not use_vp.
357 		 * Also, only AT_SIZE is needed.
358 		 */
359 
360 		tmp_attr.sa_vattr.va_mask = AT_SIZE;
361 		error = VOP_GETATTR(vp, &tmp_attr.sa_vattr, flags, cr, &smb_ct);
362 
363 		if (error != 0)
364 			return (error);
365 
366 
367 		ret_attr->sa_vattr.va_size = tmp_attr.sa_vattr.va_size;
368 	}
369 
370 	if (ret_attr->sa_vattr.va_type == VDIR) {
371 		ret_attr->sa_dosattr |= FILE_ATTRIBUTE_DIRECTORY;
372 	}
373 
374 	return (error);
375 }
376 
377 /*
378  * smb_vop_setattr()
379  *
380  * smb_fsop_setattr()/smb_vop_setattr() should always be used instead of
381  * VOP_SETATTR() when calling from the CIFS service, due to special processing
382  * for streams files.
383  *
384  * Streams have a size but otherwise do not have separate attributes from
385  * the (unnamed stream) file, i.e., the security and ownership of the file
386  * applies to the stream.  In contrast, extended attribute files, which are
387  * used to implement streams, are independent objects with their own
388  * attributes.
389  *
390  * For compatibility with streams, we set the size on the extended attribute
391  * file and apply other attributes to the (unnamed stream) file.  The one
392  * exception is that the UID and GID can be set on the stream by passing a
393  * NULL unnamed_vp, which allows callers to synchronize stream ownership
394  * with the (unnamed stream) file.
395  */
396 
397 int
398 smb_vop_setattr(vnode_t *vp, vnode_t *unnamed_vp, smb_attr_t *set_attr,
399     int flags, cred_t *cr, boolean_t no_xvattr)
400 {
401 	int error = 0;
402 	int at_size = 0;
403 	vnode_t *use_vp;
404 	xvattr_t xvattr;
405 	vattr_t *vap;
406 
407 	if (unnamed_vp) {
408 		use_vp = unnamed_vp;
409 		if (set_attr->sa_mask & SMB_AT_SIZE) {
410 			at_size = 1;
411 			set_attr->sa_mask &= ~SMB_AT_SIZE;
412 		}
413 	} else {
414 		use_vp = vp;
415 	}
416 
417 	/*
418 	 * The caller should not be setting sa_vattr.va_mask,
419 	 * but rather sa_mask.
420 	 */
421 
422 	set_attr->sa_vattr.va_mask = 0;
423 
424 	if ((no_xvattr == B_FALSE) &&
425 	    vfs_has_feature(use_vp->v_vfsp, VFSFT_XVATTR)) {
426 
427 		smb_vop_setup_xvattr(set_attr, &xvattr);
428 		vap = (vattr_t *)&xvattr;
429 	} else {
430 		smb_sa_to_va_mask(set_attr->sa_mask,
431 		    &set_attr->sa_vattr.va_mask);
432 		vap = &set_attr->sa_vattr;
433 	}
434 
435 	if ((error = VOP_SETATTR(use_vp, vap, flags, cr, &smb_ct)) != 0)
436 		return (error);
437 
438 	/*
439 	 * If the size of the stream needs to be set, set it on
440 	 * the stream file directly.  (All other indicated attributes
441 	 * are set on the stream's unnamed stream, except under the
442 	 * exception described in the function header.)
443 	 */
444 
445 	if (at_size) {
446 		/*
447 		 * set_attr->sa_vattr.va_size already contains the
448 		 * size as set by the caller
449 		 *
450 		 * Note that vp is used here, and not use_vp.
451 		 * Also, only AT_SIZE is needed.
452 		 */
453 
454 		set_attr->sa_vattr.va_mask = AT_SIZE;
455 		error = VOP_SETATTR(vp, &set_attr->sa_vattr, flags, cr,
456 		    &smb_ct);
457 	}
458 
459 	return (error);
460 }
461 
462 /*
463  * smb_vop_access
464  *
465  * This is a wrapper round VOP_ACCESS. VOP_ACCESS checks the given mode
466  * against file's ACL or Unix permissions. CIFS on the other hand needs to
467  * know if the requested operation can succeed for the given object, this
468  * requires more checks in case of DELETE bit since permissions on the parent
469  * directory are important as well. Based on Windows rules if parent's ACL
470  * grant FILE_DELETE_CHILD a file can be delete regardless of the file's
471  * permissions.
472  */
473 int
474 smb_vop_access(vnode_t *vp, int mode, int flags, vnode_t *dir_vp, cred_t *cr)
475 {
476 	int error = 0;
477 
478 	if (mode == 0)
479 		return (0);
480 
481 	if ((flags == V_ACE_MASK) && (mode & ACE_DELETE)) {
482 		if (dir_vp) {
483 			error = VOP_ACCESS(dir_vp, ACE_DELETE_CHILD, flags,
484 			    cr, NULL);
485 
486 			if (error == 0)
487 				mode &= ~ACE_DELETE;
488 		}
489 	}
490 
491 	if (mode) {
492 		error = VOP_ACCESS(vp, mode, flags, cr, NULL);
493 	}
494 
495 	return (error);
496 }
497 
498 /*
499  * smb_vop_lookup
500  *
501  * dvp:		directory vnode (in)
502  * name:	name of file to be looked up (in)
503  * vpp:		looked-up vnode (out)
504  * od_name:	on-disk name of file (out).
505  *		This parameter is optional.  If a pointer is passed in, it
506  * 		must be allocated with MAXNAMELEN bytes
507  * rootvp:	vnode of the tree root (in)
508  *		This parameter is always passed in non-NULL except at the time
509  *		of share set up.
510  */
511 
512 int
513 smb_vop_lookup(
514     vnode_t		*dvp,
515     char		*name,
516     vnode_t		**vpp,
517     char		*od_name,
518     int			flags,
519     vnode_t		*rootvp,
520     cred_t		*cr)
521 {
522 	int error = 0;
523 	int option_flags = 0;
524 	pathname_t rpn;
525 
526 	if (*name == '\0')
527 		return (EINVAL);
528 
529 	ASSERT(vpp);
530 	*vpp = NULL;
531 
532 	if ((name[0] == '.') && (name[1] == '.') && (name[2] == 0)) {
533 		if (rootvp && (dvp == rootvp)) {
534 			VN_HOLD(dvp);
535 			*vpp = dvp;
536 			return (0);
537 		}
538 
539 		if (dvp->v_flag & VROOT) {
540 			vfs_t *vfsp;
541 			vnode_t *cvp = dvp;
542 
543 			/*
544 			 * Set dvp and check for races with forced unmount
545 			 * (see lookuppnvp())
546 			 */
547 
548 			vfsp = cvp->v_vfsp;
549 			vfs_rlock_wait(vfsp);
550 			if (((dvp = cvp->v_vfsp->vfs_vnodecovered) == NULL) ||
551 			    (cvp->v_vfsp->vfs_flag & VFS_UNMOUNTED)) {
552 				vfs_unlock(vfsp);
553 				return (EIO);
554 			}
555 			vfs_unlock(vfsp);
556 		}
557 	}
558 
559 
560 
561 	if (flags & SMB_IGNORE_CASE)
562 		option_flags = FIGNORECASE;
563 
564 	pn_alloc(&rpn);
565 
566 	error = VOP_LOOKUP(dvp, name, vpp, NULL, option_flags, NULL, cr,
567 	    &smb_ct, NULL, &rpn);
568 
569 	if ((error == 0) && od_name) {
570 		bzero(od_name, MAXNAMELEN);
571 		if (option_flags == FIGNORECASE)
572 			(void) strlcpy(od_name, rpn.pn_buf, MAXNAMELEN);
573 		else
574 			(void) strlcpy(od_name, name, MAXNAMELEN);
575 	}
576 
577 	pn_free(&rpn);
578 	return (error);
579 }
580 
581 int
582 smb_vop_create(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp,
583     int flags, cred_t *cr, vsecattr_t *vsap)
584 {
585 	int error;
586 	int option_flags = 0;
587 	xvattr_t xvattr;
588 	vattr_t *vap;
589 
590 	if (flags & SMB_IGNORE_CASE)
591 		option_flags = FIGNORECASE;
592 
593 	attr->sa_vattr.va_mask = 0;
594 
595 	if (vfs_has_feature(dvp->v_vfsp, VFSFT_XVATTR)) {
596 		smb_vop_setup_xvattr(attr, &xvattr);
597 		vap = (vattr_t *)&xvattr;
598 	} else {
599 		smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask);
600 		vap = &attr->sa_vattr;
601 	}
602 
603 	error = VOP_CREATE(dvp, name, vap, EXCL, attr->sa_vattr.va_mode,
604 	    vpp, cr, option_flags, &smb_ct, vsap);
605 
606 	return (error);
607 }
608 
609 int
610 smb_vop_remove(vnode_t *dvp, char *name, int flags, cred_t *cr)
611 {
612 	int error;
613 	int option_flags = 0;
614 
615 	if (flags & SMB_IGNORE_CASE)
616 		option_flags = FIGNORECASE;
617 
618 	error = VOP_REMOVE(dvp, name, cr, &smb_ct, option_flags);
619 
620 	return (error);
621 }
622 
623 /*
624  * smb_vop_rename()
625  *
626  * The rename is for files in the same tree (identical TID) only.
627  */
628 
629 int
630 smb_vop_rename(vnode_t *from_dvp, char *from_name, vnode_t *to_dvp,
631     char *to_name, int flags, cred_t *cr)
632 {
633 	int error;
634 	int option_flags = 0;
635 
636 
637 	if (flags & SMB_IGNORE_CASE)
638 		option_flags = FIGNORECASE;
639 
640 	error = VOP_RENAME(from_dvp, from_name, to_dvp, to_name, cr,
641 	    &smb_ct, option_flags);
642 
643 	return (error);
644 }
645 
646 int
647 smb_vop_mkdir(vnode_t *dvp, char *name, smb_attr_t *attr, vnode_t **vpp,
648     int flags, cred_t *cr, vsecattr_t *vsap)
649 {
650 	int error;
651 	int option_flags = 0;
652 
653 
654 
655 	if (flags & SMB_IGNORE_CASE)
656 		option_flags = FIGNORECASE;
657 
658 	smb_sa_to_va_mask(attr->sa_mask, &attr->sa_vattr.va_mask);
659 
660 	error = VOP_MKDIR(dvp, name, &attr->sa_vattr, vpp, cr, &smb_ct,
661 	    option_flags, vsap);
662 
663 	return (error);
664 }
665 
666 /*
667  * smb_vop_rmdir()
668  *
669  * Only simple rmdir supported, consistent with NT semantics
670  * (can only remove an empty directory).
671  *
672  */
673 
674 int
675 smb_vop_rmdir(vnode_t *dvp, char *name, int flags, cred_t *cr)
676 {
677 	int error;
678 	int option_flags = 0;
679 
680 	if (flags & SMB_IGNORE_CASE)
681 		option_flags = FIGNORECASE;
682 
683 	/*
684 	 * Comments adapted from rfs_rmdir().
685 	 *
686 	 * VOP_RMDIR now takes a new third argument (the current
687 	 * directory of the process).  That's because rmdir
688 	 * wants to return EINVAL if one tries to remove ".".
689 	 * Of course, SMB servers do not know what their
690 	 * clients' current directories are.  We fake it by
691 	 * supplying a vnode known to exist and illegal to
692 	 * remove.
693 	 */
694 
695 	error = VOP_RMDIR(dvp, name, rootdir, cr, &smb_ct, option_flags);
696 	return (error);
697 }
698 
699 int
700 smb_vop_commit(vnode_t *vp, cred_t *cr)
701 {
702 	return (VOP_FSYNC(vp, 1, cr, &smb_ct));
703 }
704 
705 void
706 smb_vop_setup_xvattr(smb_attr_t *smb_attr, xvattr_t *xvattr)
707 {
708 	xoptattr_t *xoap = NULL;
709 	uint_t xva_mask;
710 
711 	/*
712 	 * Initialize xvattr, including bzero
713 	 */
714 	xva_init(xvattr);
715 	xoap = xva_getxoptattr(xvattr);
716 
717 	ASSERT(xoap);
718 
719 	/*
720 	 * Copy caller-specified classic attributes to xvattr.
721 	 * First save xvattr's mask (set in xva_init()), which
722 	 * contains AT_XVATTR.  This is |'d in later if needed.
723 	 */
724 
725 	xva_mask = xvattr->xva_vattr.va_mask;
726 	xvattr->xva_vattr = smb_attr->sa_vattr;
727 
728 	smb_sa_to_va_mask(smb_attr->sa_mask, &xvattr->xva_vattr.va_mask);
729 
730 	/*
731 	 * Do not set ctime (only the file system can do it)
732 	 */
733 
734 	xvattr->xva_vattr.va_mask &= ~AT_CTIME;
735 
736 	if (smb_attr->sa_mask & SMB_AT_DOSATTR) {
737 
738 		/*
739 		 * "|" in the original xva_mask, which contains
740 		 * AT_XVATTR
741 		 */
742 
743 		xvattr->xva_vattr.va_mask |= xva_mask;
744 
745 		XVA_SET_REQ(xvattr, XAT_ARCHIVE);
746 		XVA_SET_REQ(xvattr, XAT_SYSTEM);
747 		XVA_SET_REQ(xvattr, XAT_READONLY);
748 		XVA_SET_REQ(xvattr, XAT_HIDDEN);
749 
750 		/*
751 		 * smb_attr->sa_dosattr: If a given bit is not set,
752 		 * that indicates that the corresponding field needs
753 		 * to be updated with a "0" value.  This is done
754 		 * implicitly as the xoap->xoa_* fields were bzero'd.
755 		 */
756 
757 		if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_ARCHIVE)
758 			xoap->xoa_archive = 1;
759 
760 		if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_SYSTEM)
761 			xoap->xoa_system = 1;
762 
763 		if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_READONLY)
764 			xoap->xoa_readonly = 1;
765 
766 		if (smb_attr->sa_dosattr & FILE_ATTRIBUTE_HIDDEN)
767 			xoap->xoa_hidden = 1;
768 	}
769 
770 	if (smb_attr->sa_mask & SMB_AT_CRTIME) {
771 		/*
772 		 * "|" in the original xva_mask, which contains
773 		 * AT_XVATTR
774 		 */
775 
776 		xvattr->xva_vattr.va_mask |= xva_mask;
777 		XVA_SET_REQ(xvattr, XAT_CREATETIME);
778 		xoap->xoa_createtime = smb_attr->sa_crtime;
779 	}
780 }
781 
782 
783 /*
784  * smb_vop_readdir()
785  *
786  * Upon return, the "name" field will contain either the on-disk name or, if
787  * it needs mangling or has a case-insensitive collision, the mangled
788  * "shortname."
789  *
790  * vpp is an optional parameter.  If non-NULL, it will contain a pointer to
791  * the vnode for the name that is looked up (the vnode will be returned held).
792  *
793  * od_name is an optional parameter (NULL can be passed if the on-disk name
794  * is not needed by the caller).
795  */
796 
797 int
798 smb_vop_readdir(vnode_t *dvp, uint32_t *cookiep, char *name, int *namelen,
799     ino64_t *inop, vnode_t **vpp, char *od_name, int flags, cred_t *cr)
800 {
801 	int num_bytes;
802 	int error = 0;
803 	char *dirbuf = NULL;
804 
805 	ASSERT(dvp);
806 	ASSERT(cookiep);
807 	ASSERT(name);
808 	ASSERT(namelen);
809 	ASSERT(inop);
810 	ASSERT(cr);
811 
812 	if (dvp->v_type != VDIR) {
813 		*namelen = 0;
814 		return (ENOTDIR);
815 	}
816 
817 	if (vpp)
818 		*vpp = NULL;
819 
820 	dirbuf = kmem_zalloc(SMB_MINLEN_RDDIR_BUF, KM_SLEEP);
821 	num_bytes = SMB_MINLEN_RDDIR_BUF;
822 
823 	/*
824 	 * The goal is to retrieve the first valid entry from *cookiep
825 	 * forward.  smb_vop_readdir_readpage() collects an
826 	 * SMB_MINLEN_RDDIR_BUF-size "page" of directory entry information.
827 	 * smb_vop_readdir_entry() attempts to find the first valid entry
828 	 * in that page.
829 	 */
830 
831 	while ((error = smb_vop_readdir_readpage(dvp, dirbuf, *cookiep,
832 	    &num_bytes, cr, flags)) == 0) {
833 
834 		if (num_bytes <= 0)
835 			break;
836 
837 		name[0] = '\0';
838 
839 		error = smb_vop_readdir_entry(dvp, cookiep, name, namelen,
840 		    inop, vpp, od_name, flags, cr, dirbuf, num_bytes);
841 
842 		if (error)
843 			break;
844 
845 		if (*name)
846 			break;
847 
848 		bzero(dirbuf, SMB_MINLEN_RDDIR_BUF);
849 		num_bytes = SMB_MINLEN_RDDIR_BUF;
850 	}
851 
852 
853 	if (error) {
854 		kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF);
855 		*namelen = 0;
856 		return (error);
857 	}
858 
859 	if (num_bytes == 0) { /* EOF */
860 		kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF);
861 		*cookiep = SMB_EOF;
862 		*namelen = 0;
863 		return (0);
864 	}
865 
866 	kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF);
867 	return (0);
868 }
869 
870 /*
871  * smb_vop_readdir_readpage()
872  *
873  * Collects an SMB_MINLEN_RDDIR_BUF "page" of directory entries.  (The
874  * directory entries are returned in an fs-independent format by the
875  * underlying file system.  That is, the "page" of information returned is
876  * not literally stored on-disk in the format returned.)
877  *
878  * Much of the following is borrowed from getdents64()
879  *
880  * MAXGETDENTS_SIZE is defined in getdents.c
881  */
882 
883 #define	MAXGETDENTS_SIZE	(64 * 1024)
884 
885 static int
886 smb_vop_readdir_readpage(vnode_t *vp, void *buf, uint32_t offset, int *count,
887     cred_t *cr, int flags)
888 {
889 	int error = 0;
890 	int rdirent_flags = 0;
891 	int sink;
892 	struct uio auio;
893 	struct iovec aiov;
894 
895 	if (vp->v_type != VDIR)
896 		return (ENOTDIR);
897 
898 	/* entflags not working for streams so don't try to use them */
899 	if (!(flags & SMB_STREAM_RDDIR) &&
900 	    (vfs_has_feature(vp->v_vfsp, VFSFT_DIRENTFLAGS))) {
901 		/*
902 		 * Setting V_RDDIR_ENTFLAGS will cause the buffer to
903 		 * be filled with edirent_t structures (instead of
904 		 * dirent64_t structures).
905 		 */
906 		rdirent_flags = V_RDDIR_ENTFLAGS;
907 
908 		if (*count < sizeof (edirent_t))
909 			return (EINVAL);
910 	} else {
911 		if (*count < sizeof (dirent64_t))
912 			return (EINVAL);
913 	}
914 
915 	if (*count > MAXGETDENTS_SIZE)
916 		*count = MAXGETDENTS_SIZE;
917 
918 	aiov.iov_base = buf;
919 	aiov.iov_len = *count;
920 	auio.uio_iov = &aiov;
921 	auio.uio_iovcnt = 1;
922 	auio.uio_loffset = (uint64_t)offset;
923 	auio.uio_segflg = UIO_SYSSPACE;
924 	auio.uio_resid = *count;
925 	auio.uio_fmode = 0;
926 
927 	(void) VOP_RWLOCK(vp, V_WRITELOCK_FALSE, NULL);
928 	error = VOP_READDIR(vp, &auio, cr, &sink, &smb_ct, rdirent_flags);
929 	VOP_RWUNLOCK(vp, V_WRITELOCK_FALSE, NULL);
930 
931 	if (error) {
932 		if (error == ENOENT) {
933 			/* Fake EOF if offset is bad due to dropping of lock */
934 			*count = 0;
935 			return (0);
936 		} else {
937 			return (error);
938 		}
939 	}
940 
941 	/*
942 	 * Windows cannot handle an offset > SMB_EOF.
943 	 * Pretend we are at EOF.
944 	 */
945 
946 	if (auio.uio_loffset > SMB_EOF) {
947 		*count = 0;
948 		return (0);
949 	}
950 
951 	*count = *count - auio.uio_resid;
952 	return (0);
953 }
954 
955 /*
956  * smb_vop_readdir_entry()
957  *
958  * This function retrieves the first valid entry from the
959  * SMB_MINLEN_RDDIR_BUF-sized buffer returned by smb_vop_readdir_readpage()
960  * to smb_vop_readdir().
961  *
962  * Both dirent64_t and edirent_t structures need to be handled.  The former is
963  * needed for file systems that do not support VFSFT_DIRENTFLAGS.  The latter
964  * is required for proper handling of case collisions on file systems that
965  * support case-insensitivity.  edirent_t structures are also used for
966  * case-sensitive file systems if VFSFT_DIRENTFLAGS is supported.
967  */
968 
969 static int
970 smb_vop_readdir_entry(
971     vnode_t		*dvp,
972     uint32_t		*cookiep,
973     char		*name,
974     int			*namelen,
975     ino64_t		*inop,
976     vnode_t		**vpp,
977     char		*od_name,
978     int			flags,
979     cred_t		*cr,
980     char		*dirbuf,
981     int			 num_bytes)
982 {
983 	uint32_t next_cookie;
984 	int ebufsize;
985 	int error = 0;
986 	int len;
987 	int rc;
988 	char shortname[MANGLE_NAMELEN];
989 	char name83[MANGLE_NAMELEN];
990 	char *ebuf = NULL;
991 	edirent_t *edp;
992 	dirent64_t *dp = NULL;
993 	vnode_t *vp = NULL;
994 
995 	ASSERT(dirbuf);
996 
997 	/*
998 	 * Use edirent_t structure for both
999 	 * entflags not working for streams so don't try to use them
1000 	 */
1001 	if (!(flags & SMB_STREAM_RDDIR) &&
1002 	    (vfs_has_feature(dvp->v_vfsp, VFSFT_DIRENTFLAGS))) {
1003 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
1004 		edp = (edirent_t *)dirbuf;
1005 	} else {
1006 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
1007 		dp = (dirent64_t *)dirbuf;
1008 		ebufsize = EDIRENT_RECLEN(MAXNAMELEN);
1009 		ebuf = kmem_zalloc(ebufsize, KM_SLEEP);
1010 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
1011 		edp = (edirent_t *)ebuf;
1012 	}
1013 
1014 	while (edp) {
1015 		if (dp)
1016 			DP_TO_EDP(dp, edp);
1017 
1018 		next_cookie = (uint32_t)edp->ed_off;
1019 		if (edp->ed_ino == 0) {
1020 			*cookiep = next_cookie;
1021 
1022 			if (dp) {
1023 				/*LINTED E_BAD_PTR_CAST_ALIGN*/
1024 				DP_ADVANCE(dp, dirbuf, num_bytes);
1025 				if (dp == NULL)
1026 					edp = NULL;
1027 			} else {
1028 				/*LINTED E_BAD_PTR_CAST_ALIGN*/
1029 				EDP_ADVANCE(edp, dirbuf, num_bytes);
1030 			}
1031 			continue;
1032 		}
1033 
1034 		len = strlen(edp->ed_name);
1035 
1036 		if (*namelen < len) {
1037 			*namelen = 0;
1038 
1039 			if (ebuf)
1040 				kmem_free(ebuf, ebufsize);
1041 
1042 			return (EOVERFLOW);
1043 		}
1044 
1045 		/*
1046 		 * Do not pass SMB_IGNORE_CASE to smb_vop_lookup
1047 		 */
1048 
1049 		error = smb_vop_lookup(dvp, edp->ed_name, vpp ? vpp : &vp,
1050 		    od_name, 0, NULL, cr);
1051 
1052 		if (error) {
1053 			if (error == ENOENT) {
1054 				*cookiep = (uint32_t)next_cookie;
1055 
1056 				if (dp) {
1057 					/*LINTED E_BAD_PTR_CAST_ALIGN*/
1058 					DP_ADVANCE(dp, dirbuf, num_bytes);
1059 					if (dp == NULL)
1060 						edp = NULL;
1061 				} else {
1062 					/*LINTED E_BAD_PTR_CAST_ALIGN*/
1063 					EDP_ADVANCE(edp, dirbuf, num_bytes);
1064 				}
1065 				continue;
1066 			}
1067 
1068 
1069 			*namelen = 0;
1070 
1071 			if (ebuf)
1072 				kmem_free(ebuf, ebufsize);
1073 
1074 			return (error);
1075 		}
1076 
1077 		if ((flags & SMB_IGNORE_CASE) && ED_CASE_CONFLICTS(edp)) {
1078 			rc = smb_mangle_name(edp->ed_ino, edp->ed_name,
1079 			    shortname, name83, 1);
1080 
1081 			if (rc == 1) { /* success */
1082 				(void) strlcpy(name, shortname, *namelen + 1);
1083 				*namelen = strlen(shortname);
1084 			} else {
1085 				(void) strlcpy(name, edp->ed_name,
1086 				    *namelen + 1);
1087 				name[*namelen] = '\0';
1088 			}
1089 
1090 		} else {
1091 			(void) strlcpy(name, edp->ed_name, *namelen + 1);
1092 				*namelen = len;
1093 		}
1094 
1095 		if (vpp == NULL)
1096 			VN_RELE(vp);
1097 
1098 		if (inop)
1099 			*inop = edp->ed_ino;
1100 
1101 		*cookiep = (uint32_t)next_cookie;
1102 		break;
1103 	}
1104 
1105 	if (ebuf)
1106 		kmem_free(ebuf, ebufsize);
1107 
1108 	return (error);
1109 }
1110 
1111 /*
1112  * smb_sa_to_va_mask
1113  *
1114  * Set va_mask by running through the SMB_AT_* #define's and
1115  * setting those bits that correspond to the SMB_AT_* bits
1116  * set in sa_mask.
1117  */
1118 
1119 void
1120 smb_sa_to_va_mask(uint_t sa_mask, uint_t *va_maskp)
1121 {
1122 	int i;
1123 	uint_t smask;
1124 
1125 	smask = (sa_mask);
1126 	for (i = SMB_AT_TYPE; (i < SMB_AT_MAX) && (smask != 0); ++i) {
1127 		if (smask & 1)
1128 			*(va_maskp) |= smb_attrmap[i];
1129 
1130 		smask >>= 1;
1131 	}
1132 }
1133 
1134 /*
1135  * smb_vop_getdents()
1136  *
1137  * Upon success, the smb_node corresponding to each entry returned will
1138  * have a reference taken on it.  These will be released in
1139  * smb_trans2_find_get_dents().
1140  *
1141  * If an error is returned from this routine, a list of already processed
1142  * entries will be returned.  The smb_nodes corresponding to these entries
1143  * will be referenced, and will be released in smb_trans2_find_get_dents().
1144  *
1145  * The returned dp->d_name field will contain either the on-disk name or, if
1146  * it needs mangling or has a case-insensitive collision, the mangled
1147  * "shortname."  In this case, the on-disk name can be retrieved from the
1148  * smb_node's od_name (the smb_node is passed to smb_gather_dents_info()).
1149  */
1150 
1151 int /*ARGSUSED*/
1152 smb_vop_getdents(
1153     smb_node_t		*dir_snode,
1154     uint32_t		*cookiep,
1155     uint64_t		*verifierp,
1156     int32_t		*dircountp,
1157     char		*arg,
1158     char		*pattern,
1159     uint32_t		flags,
1160     smb_request_t	*sr,
1161     cred_t		*cr)
1162 {
1163 	int		error = 0;
1164 	int		maxentries;
1165 	int		num_bytes;
1166 	int		resid;
1167 	char		*dirbuf = NULL;
1168 	vnode_t		*dvp;
1169 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
1170 	smb_dent_info_hdr_t *ihdr = (smb_dent_info_hdr_t *)arg;
1171 
1172 	dvp = dir_snode->vp;
1173 
1174 	resid = ihdr->uio.uio_resid;
1175 	maxentries = resid / SMB_MAX_DENT_INFO_SIZE;
1176 
1177 	bzero(ihdr->iov->iov_base, resid);
1178 
1179 	dirbuf = kmem_alloc(SMB_MINLEN_RDDIR_BUF, KM_SLEEP);
1180 
1181 	while (maxentries) {
1182 
1183 		bzero(dirbuf, SMB_MINLEN_RDDIR_BUF);
1184 
1185 		num_bytes = SMB_MINLEN_RDDIR_BUF;
1186 		error = smb_vop_readdir_readpage(dvp, dirbuf, *cookiep,
1187 		    &num_bytes, cr, flags);
1188 
1189 		if (error || (num_bytes <= 0))
1190 			break;
1191 
1192 		error = smb_vop_getdents_entries(dir_snode, cookiep, dircountp,
1193 		    arg, flags, sr, cr, dirbuf, &maxentries, num_bytes,
1194 		    pattern);
1195 
1196 		if (error)
1197 			goto out;
1198 	}
1199 
1200 	if (num_bytes < 0) {
1201 		error = -1;
1202 	} else if (num_bytes == 0) {
1203 		*cookiep = SMB_EOF;
1204 		error = 0;
1205 	} else {
1206 		error = 0;
1207 	}
1208 
1209 out:
1210 	if (dirbuf)
1211 		kmem_free(dirbuf, SMB_MINLEN_RDDIR_BUF);
1212 
1213 	return (error);
1214 }
1215 
1216 /*
1217  * smb_vop_getdents_entries()
1218  *
1219  * This function retrieves names from the SMB_MINLEN_RDDIR_BUF-sized buffer
1220  * returned by smb_vop_readdir_readpage() to smb_vop_getdents().
1221  *
1222  * Both dirent64_t and edirent_t structures need to be handled.  The former is
1223  * needed for file systems that do not support VFSFT_DIRENTFLAGS.  The latter
1224  * is required for properly handling case collisions on file systems that
1225  * support case-insensitivity.  edirent_t is also used on case-sensitive
1226  * file systems where VFSFT_DIRENTFLAGS is available.
1227  */
1228 
1229 static int
1230 smb_vop_getdents_entries(
1231     smb_node_t		*dir_snode,
1232     uint32_t		*cookiep,
1233     int32_t		*dircountp,
1234     char		*arg,
1235     uint32_t		flags,
1236     smb_request_t	*sr,
1237     cred_t		*cr,
1238     char		*dirbuf,
1239     int			*maxentries,
1240     int			num_bytes,
1241     char		*pattern)
1242 {
1243 	uint32_t	next_cookie;
1244 	int		ebufsize;
1245 	char		*tmp_name;
1246 	int		error;
1247 	int		rc;
1248 	char		shortname[MANGLE_NAMELEN];
1249 	char		name83[MANGLE_NAMELEN];
1250 	char		*ebuf = NULL;
1251 	dirent64_t	*dp = NULL;
1252 	edirent_t	*edp;
1253 	smb_node_t	*ret_snode;
1254 	smb_attr_t	ret_attr;
1255 	vnode_t		*dvp;
1256 	vnode_t		*fvp;
1257 
1258 	ASSERT(dirbuf);
1259 
1260 	dvp = dir_snode->vp;
1261 
1262 	if (vfs_has_feature(dvp->v_vfsp, VFSFT_DIRENTFLAGS)) {
1263 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
1264 		edp = (edirent_t *)dirbuf;
1265 	} else {
1266 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
1267 		dp = (dirent64_t *)dirbuf;
1268 		ebufsize = EDIRENT_RECLEN(MAXNAMELEN);
1269 		ebuf = kmem_zalloc(ebufsize, KM_SLEEP);
1270 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
1271 		edp = (edirent_t *)ebuf;
1272 	}
1273 
1274 	while (edp) {
1275 		if (dp)
1276 			DP_TO_EDP(dp, edp);
1277 
1278 		if (*maxentries == 0)
1279 			break;
1280 
1281 		next_cookie = (uint32_t)edp->ed_off;
1282 
1283 		if (edp->ed_ino == 0) {
1284 			*cookiep = next_cookie;
1285 			if (dp) {
1286 				/*LINTED E_BAD_PTR_CAST_ALIGN*/
1287 				DP_ADVANCE(dp, dirbuf, num_bytes);
1288 				if (dp == NULL)
1289 					edp = NULL;
1290 			} else {
1291 				/*LINTED E_BAD_PTR_CAST_ALIGN*/
1292 				EDP_ADVANCE(edp, dirbuf, num_bytes);
1293 			}
1294 			continue;
1295 		}
1296 
1297 		error = smb_vop_lookup(dvp, edp->ed_name, &fvp,
1298 		    NULL, 0, NULL, cr);
1299 
1300 		if (error) {
1301 			if (error == ENOENT) {
1302 				*cookiep = next_cookie;
1303 				if (dp) {
1304 					/*LINTED E_BAD_PTR_CAST_ALIGN*/
1305 					DP_ADVANCE(dp, dirbuf,
1306 					    num_bytes);
1307 					if (dp == NULL)
1308 						edp = NULL;
1309 				} else {
1310 					/*LINTED E_BAD_PTR_CAST_ALIGN*/
1311 					EDP_ADVANCE(edp, dirbuf,
1312 					    num_bytes);
1313 				}
1314 				continue;
1315 			}
1316 			if (ebuf)
1317 				kmem_free(ebuf, ebufsize);
1318 
1319 			return (error);
1320 		}
1321 
1322 		ret_snode = smb_node_lookup(sr, NULL, cr, fvp,
1323 		    edp->ed_name, dir_snode, NULL, &ret_attr);
1324 
1325 		if (ret_snode == NULL) {
1326 			VN_RELE(fvp);
1327 
1328 			if (ebuf)
1329 				kmem_free(ebuf, ebufsize);
1330 
1331 			return (ENOMEM);
1332 		}
1333 
1334 		if (smb_match_name(edp->ed_ino, edp->ed_name, shortname,
1335 		    name83, pattern, (flags & SMB_IGNORE_CASE))) {
1336 
1337 			tmp_name = edp->ed_name;
1338 
1339 			if ((flags & SMB_IGNORE_CASE) &&
1340 			    ED_CASE_CONFLICTS(edp)) {
1341 				rc = smb_mangle_name(edp->ed_ino, edp->ed_name,
1342 				    shortname, name83, 1);
1343 				if (rc == 1)
1344 					tmp_name = shortname;
1345 			} else {
1346 				rc = smb_mangle_name(edp->ed_ino, edp->ed_name,
1347 				    shortname, name83, 0);
1348 			}
1349 
1350 			if (rc != 1) {
1351 				(void) strlcpy(shortname, edp->ed_name,
1352 				    MANGLE_NAMELEN);
1353 				(void) strlcpy(name83, edp->ed_name,
1354 				    MANGLE_NAMELEN);
1355 				shortname[MANGLE_NAMELEN - 1] = '\0';
1356 				name83[MANGLE_NAMELEN - 1] = '\0';
1357 			}
1358 
1359 			error = smb_gather_dents_info(arg, edp->ed_ino,
1360 			    strlen(tmp_name), tmp_name, next_cookie, dircountp,
1361 			    &ret_attr, ret_snode, shortname, name83);
1362 
1363 			if (error > 0) {
1364 				if (ebuf)
1365 					kmem_free(ebuf, ebufsize);
1366 				return (error);
1367 			}
1368 
1369 			/*
1370 			 * Treat errors from smb_gather_dents_info() that are
1371 			 * < 0 the same as EOF.
1372 			 */
1373 			if (error < 0) {
1374 				if (ebuf)
1375 					kmem_free(ebuf, ebufsize);
1376 				*maxentries = 0;
1377 				return (0);
1378 			}
1379 			(*maxentries)--;
1380 		} else {
1381 			smb_node_release(ret_snode);
1382 		}
1383 
1384 		*cookiep = next_cookie;
1385 
1386 		if (dp) {
1387 			/*LINTED E_BAD_PTR_CAST_ALIGN*/
1388 			DP_ADVANCE(dp, dirbuf, num_bytes);
1389 			if (dp == NULL)
1390 				edp = NULL;
1391 		} else {
1392 			/*LINTED E_BAD_PTR_CAST_ALIGN*/
1393 			EDP_ADVANCE(edp, dirbuf, num_bytes);
1394 		}
1395 	}
1396 
1397 	if (ebuf)
1398 		kmem_free(ebuf, ebufsize);
1399 
1400 	return (0);
1401 }
1402 
1403 /*
1404  * smb_vop_stream_lookup()
1405  *
1406  * The name returned in od_name is the on-disk name of the stream with the
1407  * SMB_STREAM_PREFIX stripped off.  od_name should be allocated to MAXNAMELEN
1408  * by the caller.
1409  */
1410 
1411 int
1412 smb_vop_stream_lookup(
1413     vnode_t		*fvp,
1414     char		*stream_name,
1415     vnode_t		**vpp,
1416     char		*od_name,
1417     vnode_t		**xattrdirvpp,
1418     int			flags,
1419     vnode_t		*rootvp,
1420     cred_t		*cr)
1421 {
1422 	char *solaris_stream_name;
1423 	char *name;
1424 	int error;
1425 
1426 	if ((error = smb_vop_lookup_xattrdir(fvp, xattrdirvpp,
1427 	    LOOKUP_XATTR | CREATE_XATTR_DIR, cr)) != 0)
1428 		return (error);
1429 
1430 	/*
1431 	 * Prepend SMB_STREAM_PREFIX to stream name
1432 	 */
1433 
1434 	solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1435 	(void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX,
1436 	    stream_name);
1437 
1438 	/*
1439 	 * "name" will hold the on-disk name returned from smb_vop_lookup
1440 	 * for the stream, including the SMB_STREAM_PREFIX.
1441 	 */
1442 
1443 	name = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
1444 
1445 	if ((error = smb_vop_lookup(*xattrdirvpp, solaris_stream_name, vpp,
1446 	    name, flags, rootvp, cr)) != 0) {
1447 		VN_RELE(*xattrdirvpp);
1448 	} else {
1449 		(void) strlcpy(od_name, &(name[SMB_STREAM_PREFIX_LEN]),
1450 		    MAXNAMELEN);
1451 	}
1452 
1453 	kmem_free(solaris_stream_name, MAXNAMELEN);
1454 	kmem_free(name, MAXNAMELEN);
1455 
1456 	return (error);
1457 }
1458 
1459 int
1460 smb_vop_stream_create(vnode_t *fvp, char *stream_name, smb_attr_t *attr,
1461     vnode_t **vpp, vnode_t **xattrdirvpp, int flags, cred_t *cr)
1462 {
1463 	char *solaris_stream_name;
1464 	int error;
1465 
1466 	if ((error = smb_vop_lookup_xattrdir(fvp, xattrdirvpp,
1467 	    LOOKUP_XATTR | CREATE_XATTR_DIR, cr)) != 0)
1468 		return (error);
1469 
1470 	/*
1471 	 * Prepend SMB_STREAM_PREFIX to stream name
1472 	 */
1473 
1474 	solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1475 	(void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX,
1476 	    stream_name);
1477 
1478 	if ((error = smb_vop_create(*xattrdirvpp, solaris_stream_name, attr,
1479 	    vpp, flags, cr, NULL)) != 0)
1480 		VN_RELE(*xattrdirvpp);
1481 
1482 	kmem_free(solaris_stream_name, MAXNAMELEN);
1483 
1484 	return (error);
1485 }
1486 
1487 int
1488 smb_vop_stream_remove(vnode_t *vp, char *stream_name, int flags, cred_t *cr)
1489 {
1490 	char *solaris_stream_name;
1491 	vnode_t *xattrdirvp;
1492 	int error;
1493 
1494 	error = smb_vop_lookup_xattrdir(vp, &xattrdirvp, LOOKUP_XATTR, cr);
1495 	if (error != 0)
1496 		return (error);
1497 
1498 	/*
1499 	 * Prepend SMB_STREAM_PREFIX to stream name
1500 	 */
1501 
1502 	solaris_stream_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
1503 	(void) sprintf(solaris_stream_name, "%s%s", SMB_STREAM_PREFIX,
1504 	    stream_name);
1505 
1506 	/* XXX might have to use kcred */
1507 	error = smb_vop_remove(xattrdirvp, solaris_stream_name, flags, cr);
1508 
1509 	kmem_free(solaris_stream_name, MAXNAMELEN);
1510 
1511 	return (error);
1512 }
1513 
1514 /*
1515  * smb_vop_stream_readdir()
1516  *
1517  * Note: stream_info.size is not filled in in this routine.
1518  * It needs to be filled in by the caller due to the parameters for getattr.
1519  *
1520  * stream_info.name is set to the on-disk stream name with the SMB_STREAM_PREFIX
1521  * removed.
1522  */
1523 
1524 int
1525 smb_vop_stream_readdir(vnode_t *fvp, uint32_t *cookiep,
1526     struct fs_stream_info *stream_info, vnode_t **vpp, vnode_t **xattrdirvpp,
1527     int flags, cred_t *cr)
1528 {
1529 	int nsize = MAXNAMELEN-1;
1530 	int error = 0;
1531 	ino64_t ino;
1532 	char *tmp_name;
1533 	vnode_t *xattrdirvp;
1534 	vnode_t *vp;
1535 
1536 	if ((error = smb_vop_lookup_xattrdir(fvp, &xattrdirvp, LOOKUP_XATTR,
1537 	    cr)) != 0)
1538 		return (error);
1539 
1540 	bzero(stream_info->name, sizeof (stream_info->name));
1541 	stream_info->size = 0;
1542 
1543 	tmp_name = kmem_zalloc(MAXNAMELEN, KM_SLEEP);
1544 
1545 	for (;;) {
1546 		error = smb_vop_readdir(xattrdirvp, cookiep, tmp_name, &nsize,
1547 		    &ino, &vp, NULL, flags | SMB_STREAM_RDDIR, cr);
1548 
1549 		if (error || (*cookiep == SMB_EOF))
1550 			break;
1551 
1552 		if (strncmp(tmp_name, SMB_STREAM_PREFIX,
1553 		    SMB_STREAM_PREFIX_LEN)) {
1554 			VN_RELE(vp);
1555 			continue;
1556 		}
1557 
1558 		tmp_name[nsize] = '\0';
1559 		(void) strlcpy(stream_info->name,
1560 		    &(tmp_name[SMB_STREAM_PREFIX_LEN]),
1561 		    sizeof (stream_info->name));
1562 
1563 		nsize -= SMB_STREAM_PREFIX_LEN;
1564 		break;
1565 	}
1566 
1567 	if ((error == 0) && nsize) {
1568 		if (vpp)
1569 			*vpp = vp;
1570 		else
1571 			VN_RELE(vp);
1572 
1573 		if (xattrdirvpp)
1574 			*xattrdirvpp = xattrdirvp;
1575 		else
1576 			VN_RELE(xattrdirvp);
1577 
1578 	} else {
1579 		VN_RELE(xattrdirvp);
1580 	}
1581 
1582 	kmem_free(tmp_name, MAXNAMELEN);
1583 
1584 	return (error);
1585 }
1586 
1587 int
1588 smb_vop_lookup_xattrdir(vnode_t *fvp, vnode_t **xattrdirvpp, int flags,
1589     cred_t *cr)
1590 {
1591 	int error;
1592 
1593 	error = VOP_LOOKUP(fvp, "", xattrdirvpp, NULL, flags, NULL, cr,
1594 	    &smb_ct, NULL, NULL);
1595 	return (error);
1596 }
1597 
1598 /*
1599  * smb_vop_traverse_check()
1600  *
1601  * This function checks to see if the passed-in vnode has a file system
1602  * mounted on it.  If it does, the mount point is "traversed" and the
1603  * vnode for the root of the file system is returned.
1604  */
1605 
1606 int
1607 smb_vop_traverse_check(vnode_t **vpp)
1608 {
1609 	int error;
1610 
1611 	if (vn_mountedvfs(*vpp) == 0)
1612 		return (0);
1613 
1614 	/*
1615 	 * traverse() may return a different held vnode, even in the error case.
1616 	 * If it returns a different vnode, it will have released the original.
1617 	 */
1618 
1619 	error = traverse(vpp);
1620 
1621 	return (error);
1622 }
1623 
1624 int /*ARGSUSED*/
1625 smb_vop_statfs(vnode_t *vp, struct statvfs64 *statp, cred_t *cr)
1626 {
1627 	int error;
1628 
1629 	error = VFS_STATVFS(vp->v_vfsp, statp);
1630 
1631 	return (error);
1632 }
1633 
1634 /*
1635  * smb_vop_acl_read
1636  *
1637  * Reads the ACL of the specified file into 'aclp'.
1638  * acl_type is the type of ACL which the filesystem supports.
1639  *
1640  * Caller has to free the allocated memory for aclp by calling
1641  * acl_free().
1642  */
1643 int
1644 smb_vop_acl_read(vnode_t *vp, acl_t **aclp, int flags, acl_type_t acl_type,
1645     cred_t *cr)
1646 {
1647 	int error;
1648 	vsecattr_t vsecattr;
1649 
1650 	ASSERT(vp);
1651 	ASSERT(aclp);
1652 
1653 	*aclp = NULL;
1654 	bzero(&vsecattr, sizeof (vsecattr_t));
1655 
1656 	switch (acl_type) {
1657 	case ACLENT_T:
1658 		vsecattr.vsa_mask = VSA_ACL | VSA_ACLCNT | VSA_DFACL |
1659 		    VSA_DFACLCNT;
1660 		break;
1661 
1662 	case ACE_T:
1663 		vsecattr.vsa_mask = VSA_ACE | VSA_ACECNT | VSA_ACE_ACLFLAGS;
1664 		break;
1665 
1666 	default:
1667 		return (EINVAL);
1668 	}
1669 
1670 	if (error = VOP_GETSECATTR(vp, &vsecattr, flags, cr, &smb_ct))
1671 		return (error);
1672 
1673 	*aclp = smb_fsacl_from_vsa(&vsecattr, acl_type);
1674 	if (vp->v_type == VDIR)
1675 		(*aclp)->acl_flags |= ACL_IS_DIR;
1676 
1677 	return (0);
1678 }
1679 
1680 /*
1681  * smb_vop_acl_write
1682  *
1683  * Writes the given ACL in aclp for the specified file.
1684  */
1685 int
1686 smb_vop_acl_write(vnode_t *vp, acl_t *aclp, int flags, cred_t *cr)
1687 {
1688 	int error;
1689 	vsecattr_t vsecattr;
1690 	int aclbsize;
1691 
1692 	ASSERT(vp);
1693 	ASSERT(aclp);
1694 
1695 	error = smb_fsacl_to_vsa(aclp, &vsecattr, &aclbsize);
1696 
1697 	if (error == 0) {
1698 		(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
1699 		error = VOP_SETSECATTR(vp, &vsecattr, flags, cr, &smb_ct);
1700 		VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
1701 	}
1702 
1703 	if (aclbsize && vsecattr.vsa_aclentp)
1704 		kmem_free(vsecattr.vsa_aclentp, aclbsize);
1705 
1706 	return (error);
1707 }
1708 
1709 /*
1710  * smb_vop_acl_type
1711  *
1712  * Determines the ACL type for the given vnode.
1713  * ACLENT_T is a Posix ACL and ACE_T is a ZFS ACL.
1714  */
1715 acl_type_t
1716 smb_vop_acl_type(vnode_t *vp)
1717 {
1718 	int error;
1719 	ulong_t whichacl;
1720 
1721 	error = VOP_PATHCONF(vp, _PC_ACL_ENABLED, &whichacl, kcred, NULL);
1722 	if (error != 0) {
1723 		/*
1724 		 * If we got an error, then the filesystem
1725 		 * likely does not understand the _PC_ACL_ENABLED
1726 		 * pathconf.  In this case, we fall back to trying
1727 		 * POSIX-draft (aka UFS-style) ACLs.
1728 		 */
1729 		whichacl = _ACL_ACLENT_ENABLED;
1730 	}
1731 
1732 	if (!(whichacl & (_ACL_ACE_ENABLED | _ACL_ACLENT_ENABLED))) {
1733 		/*
1734 		 * If the file system supports neither ACE nor
1735 		 * ACLENT ACLs we will fall back to UFS-style ACLs
1736 		 * like we did above if there was an error upon
1737 		 * calling VOP_PATHCONF.
1738 		 *
1739 		 * ACE and ACLENT type ACLs are the only interfaces
1740 		 * supported thus far.  If any other bits are set on
1741 		 * 'whichacl' upon return from VOP_PATHCONF, we will
1742 		 * ignore them.
1743 		 */
1744 		whichacl = _ACL_ACLENT_ENABLED;
1745 	}
1746 
1747 	if (whichacl == _ACL_ACLENT_ENABLED)
1748 		return (ACLENT_T);
1749 
1750 	return (ACE_T);
1751 }
1752 
1753 static int zfs_perms[] = {
1754 	ACE_READ_DATA, ACE_WRITE_DATA, ACE_APPEND_DATA, ACE_READ_NAMED_ATTRS,
1755 	ACE_WRITE_NAMED_ATTRS, ACE_EXECUTE, ACE_DELETE_CHILD,
1756 	ACE_READ_ATTRIBUTES, ACE_WRITE_ATTRIBUTES, ACE_DELETE, ACE_READ_ACL,
1757 	ACE_WRITE_ACL, ACE_WRITE_OWNER, ACE_SYNCHRONIZE
1758 };
1759 
1760 static int unix_perms[] = { VREAD, VWRITE, VEXEC };
1761 /*
1762  * smb_vop_eaccess
1763  *
1764  * Returns the effective permission of the given credential for the
1765  * specified object.
1766  *
1767  * This is just a workaround. We need VFS/FS support for this.
1768  */
1769 void
1770 smb_vop_eaccess(vnode_t *vp, int *mode, int flags, vnode_t *dir_vp, cred_t *cr)
1771 {
1772 	int error, i;
1773 	int pnum;
1774 
1775 	*mode = 0;
1776 
1777 	if (flags == V_ACE_MASK) {
1778 		pnum = sizeof (zfs_perms) / sizeof (int);
1779 
1780 		for (i = 0; i < pnum; i++) {
1781 			error = smb_vop_access(vp, zfs_perms[i], flags,
1782 			    dir_vp, cr);
1783 			if (error == 0)
1784 				*mode |= zfs_perms[i];
1785 		}
1786 	} else {
1787 		pnum = sizeof (unix_perms) / sizeof (int);
1788 
1789 		for (i = 0; i < pnum; i++) {
1790 			error = smb_vop_access(vp, unix_perms[i], flags,
1791 			    dir_vp, cr);
1792 			if (error == 0)
1793 				*mode |= unix_perms[i];
1794 		}
1795 	}
1796 }
1797 
1798 /*
1799  * smb_vop_shrlock()
1800  *
1801  * See comments for smb_fsop_shrlock()
1802  */
1803 
1804 int
1805 smb_vop_shrlock(vnode_t *vp, uint32_t uniq_fid, uint32_t desired_access,
1806     uint32_t share_access, cred_t *cr)
1807 {
1808 	struct shrlock shr;
1809 	struct shr_locowner shr_own;
1810 	short new_access = 0;
1811 	short deny = 0;
1812 	int flag = 0;
1813 	int cmd;
1814 
1815 	cmd = (nbl_need_check(vp)) ? F_SHARE_NBMAND : F_SHARE;
1816 
1817 	/*
1818 	 * Check if this is a metadata access
1819 	 */
1820 
1821 	if ((desired_access & FILE_DATA_ALL) == 0) {
1822 		new_access |= F_MDACC;
1823 	} else {
1824 		if (desired_access & (ACE_READ_DATA | ACE_EXECUTE)) {
1825 			new_access |= F_RDACC;
1826 			flag |= FREAD;
1827 		}
1828 
1829 		if (desired_access & (ACE_WRITE_DATA | ACE_APPEND_DATA |
1830 		    ACE_ADD_FILE)) {
1831 			new_access |= F_WRACC;
1832 			flag |= FWRITE;
1833 		}
1834 
1835 		if (SMB_DENY_READ(share_access)) {
1836 			deny |= F_RDDNY;
1837 		}
1838 
1839 		if (SMB_DENY_WRITE(share_access)) {
1840 			deny |= F_WRDNY;
1841 		}
1842 
1843 		if (cmd == F_SHARE_NBMAND) {
1844 			if (desired_access & ACE_DELETE)
1845 				new_access |= F_RMACC;
1846 
1847 			if (SMB_DENY_DELETE(share_access)) {
1848 				deny |= F_RMDNY;
1849 			}
1850 		}
1851 	}
1852 
1853 	shr.s_access = new_access;
1854 	shr.s_deny = deny;
1855 	shr.s_sysid = smb_ct.cc_sysid;
1856 	shr.s_pid = uniq_fid;
1857 	shr.s_own_len = sizeof (shr_own);
1858 	shr.s_owner = (caddr_t)&shr_own;
1859 	shr_own.sl_id = shr.s_sysid;
1860 	shr_own.sl_pid = shr.s_pid;
1861 
1862 	return (VOP_SHRLOCK(vp, cmd, &shr, flag, cr, NULL));
1863 }
1864 
1865 int
1866 smb_vop_unshrlock(vnode_t *vp, uint32_t uniq_fid, cred_t *cr)
1867 {
1868 	struct shrlock shr;
1869 	struct shr_locowner shr_own;
1870 
1871 	/*
1872 	 * For s_access and s_deny, we do not need to pass in the original
1873 	 * values.
1874 	 */
1875 
1876 	shr.s_access = 0;
1877 	shr.s_deny = 0;
1878 	shr.s_sysid = smb_ct.cc_sysid;
1879 	shr.s_pid = uniq_fid;
1880 	shr.s_own_len = sizeof (shr_own);
1881 	shr.s_owner = (caddr_t)&shr_own;
1882 	shr_own.sl_id = shr.s_sysid;
1883 	shr_own.sl_pid = shr.s_pid;
1884 
1885 	return (VOP_SHRLOCK(vp, F_UNSHARE, &shr, 0, cr, NULL));
1886 }
1887