xref: /xnu-8019.80.24/bsd/vfs/kpi_vfs.c (revision a325d9c4a84054e40bbe985afedcb50ab80993ea)
1 /*
2  * Copyright (c) 2000-2017 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
29 /*
30  * Copyright (c) 1989, 1993
31  *	The Regents of the University of California.  All rights reserved.
32  * (c) UNIX System Laboratories, Inc.
33  * All or some portions of this file are derived from material licensed
34  * to the University of California by American Telephone and Telegraph
35  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
36  * the permission of UNIX System Laboratories, Inc.
37  *
38  * Redistribution and use in source and binary forms, with or without
39  * modification, are permitted provided that the following conditions
40  * are met:
41  * 1. Redistributions of source code must retain the above copyright
42  *    notice, this list of conditions and the following disclaimer.
43  * 2. Redistributions in binary form must reproduce the above copyright
44  *    notice, this list of conditions and the following disclaimer in the
45  *    documentation and/or other materials provided with the distribution.
46  * 3. All advertising materials mentioning features or use of this software
47  *    must display the following acknowledgement:
48  *	This product includes software developed by the University of
49  *	California, Berkeley and its contributors.
50  * 4. Neither the name of the University nor the names of its contributors
51  *    may be used to endorse or promote products derived from this software
52  *    without specific prior written permission.
53  *
54  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
55  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
58  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
59  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
60  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
61  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
62  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
63  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64  * SUCH DAMAGE.
65  *
66  *	@(#)kpi_vfs.c
67  */
68 /*
69  * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
70  * support for mandatory and extensible security protections.  This notice
71  * is included in support of clause 2.2 (b) of the Apple Public License,
72  * Version 2.0.
73  */
74 
75 /*
76  * External virtual filesystem routines
77  */
78 
79 
80 #include <sys/param.h>
81 #include <sys/systm.h>
82 #include <sys/proc_internal.h>
83 #include <sys/kauth.h>
84 #include <sys/mount.h>
85 #include <sys/mount_internal.h>
86 #include <sys/time.h>
87 #include <sys/disk.h>
88 #include <sys/vnode_internal.h>
89 #include <sys/stat.h>
90 #include <sys/namei.h>
91 #include <sys/ucred.h>
92 #include <sys/buf.h>
93 #include <sys/errno.h>
94 #include <kern/kalloc.h>
95 #include <sys/domain.h>
96 #include <sys/mbuf.h>
97 #include <sys/syslog.h>
98 #include <sys/ubc.h>
99 #include <sys/vm.h>
100 #include <sys/sysctl.h>
101 #include <sys/filedesc.h>
102 #include <sys/event.h>
103 #include <sys/fsevents.h>
104 #include <sys/user.h>
105 #include <sys/lockf.h>
106 #include <sys/xattr.h>
107 #include <sys/kdebug.h>
108 
109 #include <kern/assert.h>
110 #include <kern/zalloc.h>
111 #include <kern/task.h>
112 #include <kern/policy_internal.h>
113 
114 #include <libkern/OSByteOrder.h>
115 
116 #include <miscfs/specfs/specdev.h>
117 
118 #include <mach/mach_types.h>
119 #include <mach/memory_object_types.h>
120 #include <mach/task.h>
121 
122 #if CONFIG_MACF
123 #include <security/mac_framework.h>
124 #endif
125 
126 #if NULLFS
127 #include <miscfs/nullfs/nullfs.h>
128 #endif
129 
130 #include <sys/sdt.h>
131 
132 #define ESUCCESS 0
133 #undef mount_t
134 #undef vnode_t
135 
136 #define COMPAT_ONLY
137 
138 #define NATIVE_XATTR(VP)  \
139 	((VP)->v_mount ? (VP)->v_mount->mnt_kern_flag & MNTK_EXTENDED_ATTRS : 0)
140 
141 #if CONFIG_APPLEDOUBLE
142 static void xattrfile_remove(vnode_t dvp, const char *basename,
143     vfs_context_t ctx, int force);
144 static void xattrfile_setattr(vnode_t dvp, const char * basename,
145     struct vnode_attr * vap, vfs_context_t ctx);
146 #endif /* CONFIG_APPLEDOUBLE */
147 
148 extern lck_rw_t rootvnode_rw_lock;
149 
150 static errno_t post_rename(vnode_t fdvp, vnode_t fvp, vnode_t tdvp, vnode_t tvp);
151 
152 KALLOC_TYPE_DEFINE(KT_VFS_CONTEXT, struct vfs_context, KT_PRIV_ACCT);
153 
154 extern int fstypenumstart;
155 char vfs_typenum_arr[13];
156 
157 LCK_GRP_DECLARE(typenum_arr_grp, "typenum array group");
158 LCK_MTX_DECLARE(vfs_typenum_mtx, &typenum_arr_grp);
159 /*
160  * vnode_setneedinactive
161  *
162  * Description: Indicate that when the last iocount on this vnode goes away,
163  *              and the usecount is also zero, we should inform the filesystem
164  *              via VNOP_INACTIVE.
165  *
166  * Parameters:  vnode_t		vnode to mark
167  *
168  * Returns:     Nothing
169  *
170  * Notes:       Notably used when we're deleting a file--we need not have a
171  *              usecount, so VNOP_INACTIVE may not get called by anyone.  We
172  *              want it called when we drop our iocount.
173  */
174 void
vnode_setneedinactive(vnode_t vp)175 vnode_setneedinactive(vnode_t vp)
176 {
177 	cache_purge(vp);
178 
179 	vnode_lock_spin(vp);
180 	vp->v_lflag |= VL_NEEDINACTIVE;
181 	vnode_unlock(vp);
182 }
183 
184 
185 /* ====================================================================== */
186 /* ************  EXTERNAL KERNEL APIS  ********************************** */
187 /* ====================================================================== */
188 
189 /*
190  * implementations of exported VFS operations
191  */
192 int
VFS_MOUNT(mount_t mp,vnode_t devvp,user_addr_t data,vfs_context_t ctx)193 VFS_MOUNT(mount_t mp, vnode_t devvp, user_addr_t data, vfs_context_t ctx)
194 {
195 	int error;
196 
197 	if ((mp == dead_mountp) || (mp->mnt_op->vfs_mount == 0)) {
198 		return ENOTSUP;
199 	}
200 
201 	if (vfs_context_is64bit(ctx)) {
202 		if (vfs_64bitready(mp)) {
203 			error = (*mp->mnt_op->vfs_mount)(mp, devvp, data, ctx);
204 		} else {
205 			error = ENOTSUP;
206 		}
207 	} else {
208 		error = (*mp->mnt_op->vfs_mount)(mp, devvp, data, ctx);
209 	}
210 
211 	return error;
212 }
213 
214 int
VFS_START(mount_t mp,int flags,vfs_context_t ctx)215 VFS_START(mount_t mp, int flags, vfs_context_t ctx)
216 {
217 	int error;
218 
219 	if ((mp == dead_mountp) || (mp->mnt_op->vfs_start == 0)) {
220 		return ENOTSUP;
221 	}
222 
223 	error = (*mp->mnt_op->vfs_start)(mp, flags, ctx);
224 
225 	return error;
226 }
227 
228 int
VFS_UNMOUNT(mount_t mp,int flags,vfs_context_t ctx)229 VFS_UNMOUNT(mount_t mp, int flags, vfs_context_t ctx)
230 {
231 	int error;
232 
233 	if ((mp == dead_mountp) || (mp->mnt_op->vfs_unmount == 0)) {
234 		return ENOTSUP;
235 	}
236 
237 	error = (*mp->mnt_op->vfs_unmount)(mp, flags, ctx);
238 
239 	return error;
240 }
241 
242 /*
243  * Returns:	0			Success
244  *		ENOTSUP			Not supported
245  *		<vfs_root>:ENOENT
246  *		<vfs_root>:???
247  *
248  * Note:	The return codes from the underlying VFS's root routine can't
249  *		be fully enumerated here, since third party VFS authors may not
250  *		limit their error returns to the ones documented here, even
251  *		though this may result in some programs functioning incorrectly.
252  *
253  *		The return codes documented above are those which may currently
254  *		be returned by HFS from hfs_vfs_root, which is a simple wrapper
255  *		for a call to hfs_vget on the volume mount point, not including
256  *		additional error codes which may be propagated from underlying
257  *		routines called by hfs_vget.
258  */
259 int
VFS_ROOT(mount_t mp,struct vnode ** vpp,vfs_context_t ctx)260 VFS_ROOT(mount_t mp, struct vnode  ** vpp, vfs_context_t ctx)
261 {
262 	int error;
263 
264 	if ((mp == dead_mountp) || (mp->mnt_op->vfs_root == 0)) {
265 		return ENOTSUP;
266 	}
267 
268 	if (ctx == NULL) {
269 		ctx = vfs_context_current();
270 	}
271 
272 	error = (*mp->mnt_op->vfs_root)(mp, vpp, ctx);
273 
274 	return error;
275 }
276 
277 int
VFS_QUOTACTL(mount_t mp,int cmd,uid_t uid,caddr_t datap,vfs_context_t ctx)278 VFS_QUOTACTL(mount_t mp, int cmd, uid_t uid, caddr_t datap, vfs_context_t ctx)
279 {
280 	int error;
281 
282 	if ((mp == dead_mountp) || (mp->mnt_op->vfs_quotactl == 0)) {
283 		return ENOTSUP;
284 	}
285 
286 	error = (*mp->mnt_op->vfs_quotactl)(mp, cmd, uid, datap, ctx);
287 
288 	return error;
289 }
290 
291 int
VFS_GETATTR(mount_t mp,struct vfs_attr * vfa,vfs_context_t ctx)292 VFS_GETATTR(mount_t mp, struct vfs_attr *vfa, vfs_context_t ctx)
293 {
294 	int error;
295 
296 	if ((mp == dead_mountp) || (mp->mnt_op->vfs_getattr == 0)) {
297 		return ENOTSUP;
298 	}
299 
300 	if (ctx == NULL) {
301 		ctx = vfs_context_current();
302 	}
303 
304 	error = (*mp->mnt_op->vfs_getattr)(mp, vfa, ctx);
305 
306 	return error;
307 }
308 
309 int
VFS_SETATTR(mount_t mp,struct vfs_attr * vfa,vfs_context_t ctx)310 VFS_SETATTR(mount_t mp, struct vfs_attr *vfa, vfs_context_t ctx)
311 {
312 	int error;
313 
314 	if ((mp == dead_mountp) || (mp->mnt_op->vfs_setattr == 0)) {
315 		return ENOTSUP;
316 	}
317 
318 	if (ctx == NULL) {
319 		ctx = vfs_context_current();
320 	}
321 
322 	error = (*mp->mnt_op->vfs_setattr)(mp, vfa, ctx);
323 
324 	return error;
325 }
326 
327 int
VFS_SYNC(mount_t mp,int flags,vfs_context_t ctx)328 VFS_SYNC(mount_t mp, int flags, vfs_context_t ctx)
329 {
330 	int error;
331 
332 	if ((mp == dead_mountp) || (mp->mnt_op->vfs_sync == 0)) {
333 		return ENOTSUP;
334 	}
335 
336 	if (ctx == NULL) {
337 		ctx = vfs_context_current();
338 	}
339 
340 	error = (*mp->mnt_op->vfs_sync)(mp, flags, ctx);
341 
342 	return error;
343 }
344 
345 int
VFS_VGET(mount_t mp,ino64_t ino,struct vnode ** vpp,vfs_context_t ctx)346 VFS_VGET(mount_t mp, ino64_t ino, struct vnode **vpp, vfs_context_t ctx)
347 {
348 	int error;
349 
350 	if ((mp == dead_mountp) || (mp->mnt_op->vfs_vget == 0)) {
351 		return ENOTSUP;
352 	}
353 
354 	if (ctx == NULL) {
355 		ctx = vfs_context_current();
356 	}
357 
358 	error = (*mp->mnt_op->vfs_vget)(mp, ino, vpp, ctx);
359 
360 	return error;
361 }
362 
363 int
VFS_FHTOVP(mount_t mp,int fhlen,unsigned char * fhp,vnode_t * vpp,vfs_context_t ctx)364 VFS_FHTOVP(mount_t mp, int fhlen, unsigned char *fhp, vnode_t *vpp, vfs_context_t ctx)
365 {
366 	int error;
367 
368 	if ((mp == dead_mountp) || (mp->mnt_op->vfs_fhtovp == 0)) {
369 		return ENOTSUP;
370 	}
371 
372 	if (ctx == NULL) {
373 		ctx = vfs_context_current();
374 	}
375 
376 	error = (*mp->mnt_op->vfs_fhtovp)(mp, fhlen, fhp, vpp, ctx);
377 
378 	return error;
379 }
380 
381 int
VFS_VPTOFH(struct vnode * vp,int * fhlenp,unsigned char * fhp,vfs_context_t ctx)382 VFS_VPTOFH(struct vnode *vp, int *fhlenp, unsigned char *fhp, vfs_context_t ctx)
383 {
384 	int error;
385 
386 	if ((vp->v_mount == dead_mountp) || (vp->v_mount->mnt_op->vfs_vptofh == 0)) {
387 		return ENOTSUP;
388 	}
389 
390 	if (ctx == NULL) {
391 		ctx = vfs_context_current();
392 	}
393 
394 	error = (*vp->v_mount->mnt_op->vfs_vptofh)(vp, fhlenp, fhp, ctx);
395 
396 	return error;
397 }
398 
399 int
VFS_IOCTL(struct mount * mp,u_long command,caddr_t data,int flags,vfs_context_t context)400 VFS_IOCTL(struct mount *mp, u_long command, caddr_t data,
401     int flags, vfs_context_t context)
402 {
403 	if (mp == dead_mountp || !mp->mnt_op->vfs_ioctl) {
404 		return ENOTSUP;
405 	}
406 
407 	return mp->mnt_op->vfs_ioctl(mp, command, data, flags,
408 	           context ?: vfs_context_current());
409 }
410 
411 int
VFS_VGET_SNAPDIR(mount_t mp,vnode_t * vpp,vfs_context_t ctx)412 VFS_VGET_SNAPDIR(mount_t mp, vnode_t *vpp, vfs_context_t ctx)
413 {
414 	int error;
415 
416 	if ((mp == dead_mountp) || (mp->mnt_op->vfs_vget_snapdir == 0)) {
417 		return ENOTSUP;
418 	}
419 
420 	if (ctx == NULL) {
421 		ctx = vfs_context_current();
422 	}
423 
424 	error = (*mp->mnt_op->vfs_vget_snapdir)(mp, vpp, ctx);
425 
426 	return error;
427 }
428 
429 /* returns the cached throttle mask for the mount_t */
430 uint64_t
vfs_throttle_mask(mount_t mp)431 vfs_throttle_mask(mount_t mp)
432 {
433 	return mp->mnt_throttle_mask;
434 }
435 
436 /* returns a  copy of vfs type name for the mount_t */
437 void
vfs_name(mount_t mp,char * buffer)438 vfs_name(mount_t mp, char *buffer)
439 {
440 	strncpy(buffer, mp->mnt_vtable->vfc_name, MFSNAMELEN);
441 }
442 
443 /* returns  vfs type number for the mount_t */
444 int
vfs_typenum(mount_t mp)445 vfs_typenum(mount_t mp)
446 {
447 	return mp->mnt_vtable->vfc_typenum;
448 }
449 
450 /* Safe to cast to "struct label*"; returns "void*" to limit dependence of mount.h on security headers.  */
451 void*
vfs_mntlabel(mount_t mp)452 vfs_mntlabel(mount_t mp)
453 {
454 	return (void*)mac_mount_label(mp);
455 }
456 
457 uint64_t
vfs_mount_id(mount_t mp)458 vfs_mount_id(mount_t mp)
459 {
460 	return mp->mnt_mount_id;
461 }
462 
463 /* returns command modifier flags of mount_t ie. MNT_CMDFLAGS */
464 uint64_t
vfs_flags(mount_t mp)465 vfs_flags(mount_t mp)
466 {
467 	return (uint64_t)(mp->mnt_flag & (MNT_CMDFLAGS | MNT_VISFLAGMASK));
468 }
469 
470 /* set any of the command modifier flags(MNT_CMDFLAGS) in mount_t */
471 void
vfs_setflags(mount_t mp,uint64_t flags)472 vfs_setflags(mount_t mp, uint64_t flags)
473 {
474 	uint32_t lflags = (uint32_t)(flags & (MNT_CMDFLAGS | MNT_VISFLAGMASK));
475 
476 	mount_lock(mp);
477 	mp->mnt_flag |= lflags;
478 	mount_unlock(mp);
479 }
480 
481 /* clear any of the command modifier flags(MNT_CMDFLAGS) in mount_t */
482 void
vfs_clearflags(mount_t mp,uint64_t flags)483 vfs_clearflags(mount_t mp, uint64_t flags)
484 {
485 	uint32_t lflags = (uint32_t)(flags & (MNT_CMDFLAGS | MNT_VISFLAGMASK));
486 
487 	mount_lock(mp);
488 	mp->mnt_flag &= ~lflags;
489 	mount_unlock(mp);
490 }
491 
492 /* Is the mount_t ronly and upgrade read/write requested? */
493 int
vfs_iswriteupgrade(mount_t mp)494 vfs_iswriteupgrade(mount_t mp) /* ronly &&  MNTK_WANTRDWR */
495 {
496 	return (mp->mnt_flag & MNT_RDONLY) && (mp->mnt_kern_flag & MNTK_WANTRDWR);
497 }
498 
499 
500 /* Is the mount_t mounted ronly */
501 int
vfs_isrdonly(mount_t mp)502 vfs_isrdonly(mount_t mp)
503 {
504 	return mp->mnt_flag & MNT_RDONLY;
505 }
506 
507 /* Is the mount_t mounted for filesystem synchronous writes? */
508 int
vfs_issynchronous(mount_t mp)509 vfs_issynchronous(mount_t mp)
510 {
511 	return mp->mnt_flag & MNT_SYNCHRONOUS;
512 }
513 
514 /* Is the mount_t mounted read/write? */
515 int
vfs_isrdwr(mount_t mp)516 vfs_isrdwr(mount_t mp)
517 {
518 	return (mp->mnt_flag & MNT_RDONLY) == 0;
519 }
520 
521 
522 /* Is mount_t marked for update (ie MNT_UPDATE) */
523 int
vfs_isupdate(mount_t mp)524 vfs_isupdate(mount_t mp)
525 {
526 	return mp->mnt_flag & MNT_UPDATE;
527 }
528 
529 
530 /* Is mount_t marked for reload (ie MNT_RELOAD) */
531 int
vfs_isreload(mount_t mp)532 vfs_isreload(mount_t mp)
533 {
534 	return (mp->mnt_flag & MNT_UPDATE) && (mp->mnt_flag & MNT_RELOAD);
535 }
536 
537 /* Is mount_t marked for forced unmount (ie MNT_FORCE or MNTK_FRCUNMOUNT) */
538 int
vfs_isforce(mount_t mp)539 vfs_isforce(mount_t mp)
540 {
541 	if (mp->mnt_lflag & MNT_LFORCE) {
542 		return 1;
543 	} else {
544 		return 0;
545 	}
546 }
547 
548 int
vfs_isunmount(mount_t mp)549 vfs_isunmount(mount_t mp)
550 {
551 	if ((mp->mnt_lflag & MNT_LUNMOUNT)) {
552 		return 1;
553 	} else {
554 		return 0;
555 	}
556 }
557 
558 int
vfs_64bitready(mount_t mp)559 vfs_64bitready(mount_t mp)
560 {
561 	if ((mp->mnt_vtable->vfc_vfsflags & VFC_VFS64BITREADY)) {
562 		return 1;
563 	} else {
564 		return 0;
565 	}
566 }
567 
568 
569 int
vfs_authcache_ttl(mount_t mp)570 vfs_authcache_ttl(mount_t mp)
571 {
572 	if ((mp->mnt_kern_flag & (MNTK_AUTH_OPAQUE | MNTK_AUTH_CACHE_TTL))) {
573 		return mp->mnt_authcache_ttl;
574 	} else {
575 		return CACHED_RIGHT_INFINITE_TTL;
576 	}
577 }
578 
579 void
vfs_setauthcache_ttl(mount_t mp,int ttl)580 vfs_setauthcache_ttl(mount_t mp, int ttl)
581 {
582 	mount_lock(mp);
583 	mp->mnt_kern_flag |= MNTK_AUTH_CACHE_TTL;
584 	mp->mnt_authcache_ttl = ttl;
585 	mount_unlock(mp);
586 }
587 
588 void
vfs_clearauthcache_ttl(mount_t mp)589 vfs_clearauthcache_ttl(mount_t mp)
590 {
591 	mount_lock(mp);
592 	mp->mnt_kern_flag &= ~MNTK_AUTH_CACHE_TTL;
593 	/*
594 	 * back to the default TTL value in case
595 	 * MNTK_AUTH_OPAQUE is set on this mount
596 	 */
597 	mp->mnt_authcache_ttl = CACHED_LOOKUP_RIGHT_TTL;
598 	mount_unlock(mp);
599 }
600 
601 int
vfs_authopaque(mount_t mp)602 vfs_authopaque(mount_t mp)
603 {
604 	if ((mp->mnt_kern_flag & MNTK_AUTH_OPAQUE)) {
605 		return 1;
606 	} else {
607 		return 0;
608 	}
609 }
610 
611 int
vfs_authopaqueaccess(mount_t mp)612 vfs_authopaqueaccess(mount_t mp)
613 {
614 	if ((mp->mnt_kern_flag & MNTK_AUTH_OPAQUE_ACCESS)) {
615 		return 1;
616 	} else {
617 		return 0;
618 	}
619 }
620 
621 void
vfs_setauthopaque(mount_t mp)622 vfs_setauthopaque(mount_t mp)
623 {
624 	mount_lock(mp);
625 	mp->mnt_kern_flag |= MNTK_AUTH_OPAQUE;
626 	mount_unlock(mp);
627 }
628 
629 void
vfs_setauthopaqueaccess(mount_t mp)630 vfs_setauthopaqueaccess(mount_t mp)
631 {
632 	mount_lock(mp);
633 	mp->mnt_kern_flag |= MNTK_AUTH_OPAQUE_ACCESS;
634 	mount_unlock(mp);
635 }
636 
637 void
vfs_clearauthopaque(mount_t mp)638 vfs_clearauthopaque(mount_t mp)
639 {
640 	mount_lock(mp);
641 	mp->mnt_kern_flag &= ~MNTK_AUTH_OPAQUE;
642 	mount_unlock(mp);
643 }
644 
645 void
vfs_clearauthopaqueaccess(mount_t mp)646 vfs_clearauthopaqueaccess(mount_t mp)
647 {
648 	mount_lock(mp);
649 	mp->mnt_kern_flag &= ~MNTK_AUTH_OPAQUE_ACCESS;
650 	mount_unlock(mp);
651 }
652 
653 void
vfs_setextendedsecurity(mount_t mp)654 vfs_setextendedsecurity(mount_t mp)
655 {
656 	mount_lock(mp);
657 	mp->mnt_kern_flag |= MNTK_EXTENDED_SECURITY;
658 	mount_unlock(mp);
659 }
660 
661 void
vfs_setmntsystem(mount_t mp)662 vfs_setmntsystem(mount_t mp)
663 {
664 	mount_lock(mp);
665 	mp->mnt_kern_flag |= MNTK_SYSTEM;
666 	mount_unlock(mp);
667 }
668 
669 void
vfs_setmntsystemdata(mount_t mp)670 vfs_setmntsystemdata(mount_t mp)
671 {
672 	mount_lock(mp);
673 	mp->mnt_kern_flag |= MNTK_SYSTEMDATA;
674 	mount_unlock(mp);
675 }
676 
677 void
vfs_setmntswap(mount_t mp)678 vfs_setmntswap(mount_t mp)
679 {
680 	mount_lock(mp);
681 	mp->mnt_kern_flag |= (MNTK_SYSTEM | MNTK_SWAP_MOUNT);
682 	mount_unlock(mp);
683 }
684 
685 void
vfs_clearextendedsecurity(mount_t mp)686 vfs_clearextendedsecurity(mount_t mp)
687 {
688 	mount_lock(mp);
689 	mp->mnt_kern_flag &= ~MNTK_EXTENDED_SECURITY;
690 	mount_unlock(mp);
691 }
692 
693 void
vfs_setnoswap(mount_t mp)694 vfs_setnoswap(mount_t mp)
695 {
696 	mount_lock(mp);
697 	mp->mnt_kern_flag |= MNTK_NOSWAP;
698 	mount_unlock(mp);
699 }
700 
701 void
vfs_clearnoswap(mount_t mp)702 vfs_clearnoswap(mount_t mp)
703 {
704 	mount_lock(mp);
705 	mp->mnt_kern_flag &= ~MNTK_NOSWAP;
706 	mount_unlock(mp);
707 }
708 
709 int
vfs_extendedsecurity(mount_t mp)710 vfs_extendedsecurity(mount_t mp)
711 {
712 	return mp->mnt_kern_flag & MNTK_EXTENDED_SECURITY;
713 }
714 
715 /* returns the max size of short symlink in this mount_t */
716 uint32_t
vfs_maxsymlen(mount_t mp)717 vfs_maxsymlen(mount_t mp)
718 {
719 	return mp->mnt_maxsymlinklen;
720 }
721 
722 /* set  max size of short symlink on mount_t */
723 void
vfs_setmaxsymlen(mount_t mp,uint32_t symlen)724 vfs_setmaxsymlen(mount_t mp, uint32_t symlen)
725 {
726 	mp->mnt_maxsymlinklen = symlen;
727 }
728 
729 boolean_t
vfs_is_basesystem(mount_t mp)730 vfs_is_basesystem(mount_t mp)
731 {
732 	return ((mp->mnt_supl_kern_flag & MNTK_SUPL_BASESYSTEM) == 0) ? false : true;
733 }
734 
735 /* return a pointer to the RO vfs_statfs associated with mount_t */
736 struct vfsstatfs *
vfs_statfs(mount_t mp)737 vfs_statfs(mount_t mp)
738 {
739 	return &mp->mnt_vfsstat;
740 }
741 
742 int
vfs_getattr(mount_t mp,struct vfs_attr * vfa,vfs_context_t ctx)743 vfs_getattr(mount_t mp, struct vfs_attr *vfa, vfs_context_t ctx)
744 {
745 	int             error;
746 
747 	if ((error = VFS_GETATTR(mp, vfa, ctx)) != 0) {
748 		return error;
749 	}
750 
751 	/*
752 	 * If we have a filesystem create time, use it to default some others.
753 	 */
754 	if (VFSATTR_IS_SUPPORTED(vfa, f_create_time)) {
755 		if (VFSATTR_IS_ACTIVE(vfa, f_modify_time) && !VFSATTR_IS_SUPPORTED(vfa, f_modify_time)) {
756 			VFSATTR_RETURN(vfa, f_modify_time, vfa->f_create_time);
757 		}
758 	}
759 
760 	return 0;
761 }
762 
763 int
vfs_setattr(mount_t mp,struct vfs_attr * vfa,vfs_context_t ctx)764 vfs_setattr(mount_t mp, struct vfs_attr *vfa, vfs_context_t ctx)
765 {
766 	int error;
767 
768 	/*
769 	 * with a read-only system volume, we need to allow rename of the root volume
770 	 * even if it's read-only.  Don't return EROFS here if setattr changes only
771 	 * the volume name
772 	 */
773 	if (vfs_isrdonly(mp) &&
774 	    !((strcmp(mp->mnt_vfsstat.f_fstypename, "apfs") == 0) && (vfa->f_active == VFSATTR_f_vol_name))) {
775 		return EROFS;
776 	}
777 
778 	error = VFS_SETATTR(mp, vfa, ctx);
779 
780 	/*
781 	 * If we had alternate ways of setting vfs attributes, we'd
782 	 * fall back here.
783 	 */
784 
785 	return error;
786 }
787 
788 /* return the private data handle stored in mount_t */
789 void *
vfs_fsprivate(mount_t mp)790 vfs_fsprivate(mount_t mp)
791 {
792 	return mp->mnt_data;
793 }
794 
795 /* set the private data handle in mount_t */
796 void
vfs_setfsprivate(mount_t mp,void * mntdata)797 vfs_setfsprivate(mount_t mp, void *mntdata)
798 {
799 	mount_lock(mp);
800 	mp->mnt_data = mntdata;
801 	mount_unlock(mp);
802 }
803 
804 /* query whether the mount point supports native EAs */
805 int
vfs_nativexattrs(mount_t mp)806 vfs_nativexattrs(mount_t mp)
807 {
808 	return mp->mnt_kern_flag & MNTK_EXTENDED_ATTRS;
809 }
810 
811 /*
812  * return the block size of the underlying
813  * device associated with mount_t
814  */
815 int
vfs_devblocksize(mount_t mp)816 vfs_devblocksize(mount_t mp)
817 {
818 	return mp->mnt_devblocksize;
819 }
820 
821 /*
822  * Returns vnode with an iocount that must be released with vnode_put()
823  */
824 vnode_t
vfs_vnodecovered(mount_t mp)825 vfs_vnodecovered(mount_t mp)
826 {
827 	vnode_t vp = mp->mnt_vnodecovered;
828 	if ((vp == NULL) || (vnode_getwithref(vp) != 0)) {
829 		return NULL;
830 	} else {
831 		return vp;
832 	}
833 }
834 
835 /*
836  * Returns device vnode backing a mountpoint with an iocount (if valid vnode exists).
837  * The iocount must be released with vnode_put().  Note that this KPI is subtle
838  * with respect to the validity of using this device vnode for anything substantial
839  * (which is discouraged).  If commands are sent to the device driver without
840  * taking proper steps to ensure that the device is still open, chaos may ensue.
841  * Similarly, this routine should only be called if there is some guarantee that
842  * the mount itself is still valid.
843  */
844 vnode_t
vfs_devvp(mount_t mp)845 vfs_devvp(mount_t mp)
846 {
847 	vnode_t vp = mp->mnt_devvp;
848 
849 	if ((vp != NULLVP) && (vnode_get(vp) == 0)) {
850 		return vp;
851 	}
852 
853 	return NULLVP;
854 }
855 
856 /*
857  * return the io attributes associated with mount_t
858  */
859 void
vfs_ioattr(mount_t mp,struct vfsioattr * ioattrp)860 vfs_ioattr(mount_t mp, struct vfsioattr *ioattrp)
861 {
862 	ioattrp->io_reserved[0] = NULL;
863 	ioattrp->io_reserved[1] = NULL;
864 	if (mp == NULL) {
865 		ioattrp->io_maxreadcnt  = MAXPHYS;
866 		ioattrp->io_maxwritecnt = MAXPHYS;
867 		ioattrp->io_segreadcnt  = 32;
868 		ioattrp->io_segwritecnt = 32;
869 		ioattrp->io_maxsegreadsize  = MAXPHYS;
870 		ioattrp->io_maxsegwritesize = MAXPHYS;
871 		ioattrp->io_devblocksize = DEV_BSIZE;
872 		ioattrp->io_flags = 0;
873 		ioattrp->io_max_swappin_available = 0;
874 	} else {
875 		ioattrp->io_maxreadcnt  = mp->mnt_maxreadcnt;
876 		ioattrp->io_maxwritecnt = mp->mnt_maxwritecnt;
877 		ioattrp->io_segreadcnt  = mp->mnt_segreadcnt;
878 		ioattrp->io_segwritecnt = mp->mnt_segwritecnt;
879 		ioattrp->io_maxsegreadsize  = mp->mnt_maxsegreadsize;
880 		ioattrp->io_maxsegwritesize = mp->mnt_maxsegwritesize;
881 		ioattrp->io_devblocksize = mp->mnt_devblocksize;
882 		ioattrp->io_flags = mp->mnt_ioflags;
883 		ioattrp->io_max_swappin_available = mp->mnt_max_swappin_available;
884 	}
885 }
886 
887 
888 /*
889  * set the IO attributes associated with mount_t
890  */
891 void
vfs_setioattr(mount_t mp,struct vfsioattr * ioattrp)892 vfs_setioattr(mount_t mp, struct vfsioattr * ioattrp)
893 {
894 	if (mp == NULL) {
895 		return;
896 	}
897 	mp->mnt_maxreadcnt  = ioattrp->io_maxreadcnt;
898 	mp->mnt_maxwritecnt = ioattrp->io_maxwritecnt;
899 	mp->mnt_segreadcnt  = ioattrp->io_segreadcnt;
900 	mp->mnt_segwritecnt = ioattrp->io_segwritecnt;
901 	mp->mnt_maxsegreadsize = ioattrp->io_maxsegreadsize;
902 	mp->mnt_maxsegwritesize = ioattrp->io_maxsegwritesize;
903 	mp->mnt_devblocksize = ioattrp->io_devblocksize;
904 	mp->mnt_ioflags = ioattrp->io_flags;
905 	mp->mnt_max_swappin_available = ioattrp->io_max_swappin_available;
906 }
907 
908 /*
909  * Add a new filesystem into the kernel specified in passed in
910  * vfstable structure. It fills in the vnode
911  * dispatch vector that is to be passed to when vnodes are created.
912  * It returns a handle which is to be used to when the FS is to be removed
913  */
914 typedef int (*PFI)(void *);
915 extern int vfs_opv_numops;
916 errno_t
vfs_fsadd(struct vfs_fsentry * vfe,vfstable_t * handle)917 vfs_fsadd(struct vfs_fsentry *vfe, vfstable_t *handle)
918 {
919 	struct vfstable *newvfstbl = NULL;
920 	int     i, j;
921 	int(***opv_desc_vector_p)(void *);
922 	int(**opv_desc_vector)(void *);
923 	const struct vnodeopv_entry_desc        *opve_descp;
924 	int desccount;
925 	int descsize;
926 	PFI *descptr;
927 
928 	/*
929 	 * This routine is responsible for all the initialization that would
930 	 * ordinarily be done as part of the system startup;
931 	 */
932 
933 	if (vfe == (struct vfs_fsentry *)0) {
934 		return EINVAL;
935 	}
936 
937 	desccount = vfe->vfe_vopcnt;
938 	if ((desccount <= 0) || ((desccount > 8)) || (vfe->vfe_vfsops == (struct vfsops *)NULL)
939 	    || (vfe->vfe_opvdescs == (struct vnodeopv_desc **)NULL)) {
940 		return EINVAL;
941 	}
942 
943 	/* Non-threadsafe filesystems are not supported */
944 	if ((vfe->vfe_flags &  (VFS_TBLTHREADSAFE | VFS_TBLFSNODELOCK)) == 0) {
945 		return EINVAL;
946 	}
947 
948 	newvfstbl = kalloc_type(struct vfstable, Z_WAITOK | Z_ZERO);
949 	newvfstbl->vfc_vfsops = vfe->vfe_vfsops;
950 	strncpy(&newvfstbl->vfc_name[0], vfe->vfe_fsname, MFSNAMELEN);
951 	if ((vfe->vfe_flags & VFS_TBLNOTYPENUM)) {
952 		int tmp;
953 		int found = 0;
954 		lck_mtx_lock(&vfs_typenum_mtx);
955 		for (tmp = fstypenumstart; tmp < OID_AUTO_START; tmp++) {
956 			if (isclr(vfs_typenum_arr, tmp)) {
957 				newvfstbl->vfc_typenum = tmp;
958 				setbit(vfs_typenum_arr, tmp);
959 				found = 1;
960 				break;
961 			}
962 		}
963 		if (!found) {
964 			lck_mtx_unlock(&vfs_typenum_mtx);
965 			return EINVAL;
966 		}
967 		if (maxvfstypenum < OID_AUTO_START) {
968 			/* getvfsbyname checks up to but not including maxvfstypenum */
969 			maxvfstypenum = newvfstbl->vfc_typenum + 1;
970 		}
971 		lck_mtx_unlock(&vfs_typenum_mtx);
972 	} else {
973 		newvfstbl->vfc_typenum = vfe->vfe_fstypenum;
974 		lck_mtx_lock(&vfs_typenum_mtx);
975 		setbit(vfs_typenum_arr, newvfstbl->vfc_typenum);
976 		if (newvfstbl->vfc_typenum >= maxvfstypenum) {
977 			maxvfstypenum = newvfstbl->vfc_typenum + 1;
978 		}
979 		lck_mtx_unlock(&vfs_typenum_mtx);
980 	}
981 
982 
983 	newvfstbl->vfc_refcount = 0;
984 	newvfstbl->vfc_flags = 0;
985 	newvfstbl->vfc_mountroot = NULL;
986 	newvfstbl->vfc_next = NULL;
987 	newvfstbl->vfc_vfsflags = 0;
988 	if (vfe->vfe_flags &  VFS_TBL64BITREADY) {
989 		newvfstbl->vfc_vfsflags |= VFC_VFS64BITREADY;
990 	}
991 	if (vfe->vfe_flags &  VFS_TBLVNOP_PAGEINV2) {
992 		newvfstbl->vfc_vfsflags |= VFC_VFSVNOP_PAGEINV2;
993 	}
994 	if (vfe->vfe_flags &  VFS_TBLVNOP_PAGEOUTV2) {
995 		newvfstbl->vfc_vfsflags |= VFC_VFSVNOP_PAGEOUTV2;
996 	}
997 	if ((vfe->vfe_flags & VFS_TBLLOCALVOL) == VFS_TBLLOCALVOL) {
998 		newvfstbl->vfc_flags |= MNT_LOCAL;
999 	}
1000 	if ((vfe->vfe_flags & VFS_TBLLOCALVOL) && (vfe->vfe_flags & VFS_TBLGENERICMNTARGS) == 0) {
1001 		newvfstbl->vfc_vfsflags |= VFC_VFSLOCALARGS;
1002 	} else {
1003 		newvfstbl->vfc_vfsflags |= VFC_VFSGENERICARGS;
1004 	}
1005 
1006 	if (vfe->vfe_flags &  VFS_TBLNATIVEXATTR) {
1007 		newvfstbl->vfc_vfsflags |= VFC_VFSNATIVEXATTR;
1008 	}
1009 	if (vfe->vfe_flags &  VFS_TBLUNMOUNT_PREFLIGHT) {
1010 		newvfstbl->vfc_vfsflags |= VFC_VFSPREFLIGHT;
1011 	}
1012 	if (vfe->vfe_flags &  VFS_TBLREADDIR_EXTENDED) {
1013 		newvfstbl->vfc_vfsflags |= VFC_VFSREADDIR_EXTENDED;
1014 	}
1015 	if (vfe->vfe_flags & VFS_TBLNOMACLABEL) {
1016 		newvfstbl->vfc_vfsflags |= VFC_VFSNOMACLABEL;
1017 	}
1018 	if (vfe->vfe_flags & VFS_TBLVNOP_NOUPDATEID_RENAME) {
1019 		newvfstbl->vfc_vfsflags |= VFC_VFSVNOP_NOUPDATEID_RENAME;
1020 	}
1021 	if (vfe->vfe_flags & VFS_TBLVNOP_SECLUDE_RENAME) {
1022 		newvfstbl->vfc_vfsflags |= VFC_VFSVNOP_SECLUDE_RENAME;
1023 	}
1024 	if (vfe->vfe_flags & VFS_TBLCANMOUNTROOT) {
1025 		newvfstbl->vfc_vfsflags |= VFC_VFSCANMOUNTROOT;
1026 	}
1027 
1028 	/*
1029 	 * Allocate and init the vectors.
1030 	 * Also handle backwards compatibility.
1031 	 *
1032 	 * We allocate one large block to hold all <desccount>
1033 	 * vnode operation vectors stored contiguously.
1034 	 */
1035 	/* XXX - shouldn't be M_TEMP */
1036 
1037 	descsize = desccount * vfs_opv_numops;
1038 	descptr = kalloc_type(PFI, descsize, Z_WAITOK | Z_ZERO);
1039 
1040 	newvfstbl->vfc_descptr = descptr;
1041 	newvfstbl->vfc_descsize = descsize;
1042 
1043 	newvfstbl->vfc_sysctl = NULL;
1044 
1045 	for (i = 0; i < desccount; i++) {
1046 		opv_desc_vector_p = vfe->vfe_opvdescs[i]->opv_desc_vector_p;
1047 		/*
1048 		 * Fill in the caller's pointer to the start of the i'th vector.
1049 		 * They'll need to supply it when calling vnode_create.
1050 		 */
1051 		opv_desc_vector = descptr + i * vfs_opv_numops;
1052 		*opv_desc_vector_p = opv_desc_vector;
1053 
1054 		for (j = 0; vfe->vfe_opvdescs[i]->opv_desc_ops[j].opve_op; j++) {
1055 			opve_descp = &(vfe->vfe_opvdescs[i]->opv_desc_ops[j]);
1056 
1057 			/* Silently skip known-disabled operations */
1058 			if (opve_descp->opve_op->vdesc_flags & VDESC_DISABLED) {
1059 				printf("vfs_fsadd: Ignoring reference in %p to disabled operation %s.\n",
1060 				    vfe->vfe_opvdescs[i], opve_descp->opve_op->vdesc_name);
1061 				continue;
1062 			}
1063 
1064 			/*
1065 			 * Sanity check:  is this operation listed
1066 			 * in the list of operations?  We check this
1067 			 * by seeing if its offset is zero.  Since
1068 			 * the default routine should always be listed
1069 			 * first, it should be the only one with a zero
1070 			 * offset.  Any other operation with a zero
1071 			 * offset is probably not listed in
1072 			 * vfs_op_descs, and so is probably an error.
1073 			 *
1074 			 * A panic here means the layer programmer
1075 			 * has committed the all-too common bug
1076 			 * of adding a new operation to the layer's
1077 			 * list of vnode operations but
1078 			 * not adding the operation to the system-wide
1079 			 * list of supported operations.
1080 			 */
1081 			if (opve_descp->opve_op->vdesc_offset == 0 &&
1082 			    opve_descp->opve_op != VDESC(vnop_default)) {
1083 				printf("vfs_fsadd: operation %s not listed in %s.\n",
1084 				    opve_descp->opve_op->vdesc_name,
1085 				    "vfs_op_descs");
1086 				panic("vfs_fsadd: bad operation");
1087 			}
1088 			/*
1089 			 * Fill in this entry.
1090 			 */
1091 			opv_desc_vector[opve_descp->opve_op->vdesc_offset] =
1092 			    opve_descp->opve_impl;
1093 		}
1094 
1095 		/*
1096 		 * Finally, go back and replace unfilled routines
1097 		 * with their default.  (Sigh, an O(n^3) algorithm.  I
1098 		 * could make it better, but that'd be work, and n is small.)
1099 		 */
1100 		opv_desc_vector_p = vfe->vfe_opvdescs[i]->opv_desc_vector_p;
1101 
1102 		/*
1103 		 * Force every operations vector to have a default routine.
1104 		 */
1105 		opv_desc_vector = *opv_desc_vector_p;
1106 		if (opv_desc_vector[VOFFSET(vnop_default)] == NULL) {
1107 			panic("vfs_fsadd: operation vector without default routine.");
1108 		}
1109 		for (j = 0; j < vfs_opv_numops; j++) {
1110 			if (opv_desc_vector[j] == NULL) {
1111 				opv_desc_vector[j] =
1112 				    opv_desc_vector[VOFFSET(vnop_default)];
1113 			}
1114 		}
1115 	} /* end of each vnodeopv_desc parsing */
1116 
1117 	*handle = vfstable_add(newvfstbl);
1118 
1119 	if (newvfstbl->vfc_vfsops->vfs_init) {
1120 		struct vfsconf vfsc;
1121 		bzero(&vfsc, sizeof(struct vfsconf));
1122 		vfsc.vfc_reserved1 = 0;
1123 		bcopy((*handle)->vfc_name, vfsc.vfc_name, sizeof(vfsc.vfc_name));
1124 		vfsc.vfc_typenum = (*handle)->vfc_typenum;
1125 		vfsc.vfc_refcount = (*handle)->vfc_refcount;
1126 		vfsc.vfc_flags = (*handle)->vfc_flags;
1127 		vfsc.vfc_reserved2 = 0;
1128 		vfsc.vfc_reserved3 = 0;
1129 
1130 		(*newvfstbl->vfc_vfsops->vfs_init)(&vfsc);
1131 	}
1132 
1133 	kfree_type(struct vfstable, newvfstbl);
1134 
1135 	return 0;
1136 }
1137 
1138 /*
1139  * Removes the filesystem from kernel.
1140  * The argument passed in is the handle that was given when
1141  * file system was added
1142  */
1143 errno_t
vfs_fsremove(vfstable_t handle)1144 vfs_fsremove(vfstable_t handle)
1145 {
1146 	struct vfstable * vfstbl =  (struct vfstable *)handle;
1147 	void *old_desc = NULL;
1148 	size_t descsize = 0;
1149 	errno_t err;
1150 
1151 	/* Preflight check for any mounts */
1152 	mount_list_lock();
1153 	if (vfstbl->vfc_refcount != 0) {
1154 		mount_list_unlock();
1155 		return EBUSY;
1156 	}
1157 
1158 	/* Free the spot in vfs_typenum_arr */
1159 	lck_mtx_lock(&vfs_typenum_mtx);
1160 	clrbit(vfs_typenum_arr, handle->vfc_typenum);
1161 	if (maxvfstypenum == handle->vfc_typenum) {
1162 		maxvfstypenum--;
1163 	}
1164 	lck_mtx_unlock(&vfs_typenum_mtx);
1165 
1166 	/*
1167 	 * save the old descriptor; the free cannot occur unconditionally,
1168 	 * since vfstable_del() may fail.
1169 	 */
1170 	if (vfstbl->vfc_descptr && vfstbl->vfc_descsize) {
1171 		old_desc = vfstbl->vfc_descptr;
1172 		descsize = vfstbl->vfc_descsize;
1173 	}
1174 	err = vfstable_del(vfstbl);
1175 
1176 	mount_list_unlock();
1177 
1178 	/* free the descriptor if the delete was successful */
1179 	if (err == 0) {
1180 		kfree_type(PFI, descsize, old_desc);
1181 	}
1182 
1183 	return err;
1184 }
1185 
1186 void
vfs_setowner(mount_t mp,uid_t uid,gid_t gid)1187 vfs_setowner(mount_t mp, uid_t uid, gid_t gid)
1188 {
1189 	mp->mnt_fsowner = uid;
1190 	mp->mnt_fsgroup = gid;
1191 }
1192 
1193 /*
1194  * Callers should be careful how they use this; accessing
1195  * mnt_last_write_completed_timestamp is not thread-safe.  Writing to
1196  * it isn't either.  Point is: be prepared to deal with strange values
1197  * being returned.
1198  */
1199 uint64_t
vfs_idle_time(mount_t mp)1200 vfs_idle_time(mount_t mp)
1201 {
1202 	if (mp->mnt_pending_write_size) {
1203 		return 0;
1204 	}
1205 
1206 	struct timeval now;
1207 
1208 	microuptime(&now);
1209 
1210 	return (now.tv_sec
1211 	       - mp->mnt_last_write_completed_timestamp.tv_sec) * 1000000
1212 	       + now.tv_usec - mp->mnt_last_write_completed_timestamp.tv_usec;
1213 }
1214 
1215 int
vfs_context_pid(vfs_context_t ctx)1216 vfs_context_pid(vfs_context_t ctx)
1217 {
1218 	return proc_pid(vfs_context_proc(ctx));
1219 }
1220 
1221 int
vfs_context_copy_audit_token(vfs_context_t ctx,audit_token_t * token)1222 vfs_context_copy_audit_token(vfs_context_t ctx, audit_token_t *token)
1223 {
1224 	kern_return_t           err;
1225 	task_t                  task = NULL;
1226 	mach_msg_type_number_t  info_size = TASK_AUDIT_TOKEN_COUNT;
1227 
1228 	if (ctx != NULL && ctx->vc_thread != NULL) {
1229 		task = get_threadtask(ctx->vc_thread);
1230 	}
1231 
1232 	if (task == NULL) {
1233 		// Not sure how this would happen; we are supposed to be
1234 		// in the middle of using the context. Regardless, don't
1235 		// wander off a NULL pointer.
1236 		return ESRCH;
1237 	}
1238 
1239 	err = task_info(task, TASK_AUDIT_TOKEN, (integer_t *)token, &info_size);
1240 	return (err) ? ESRCH : 0;
1241 }
1242 
1243 int
vfs_context_suser(vfs_context_t ctx)1244 vfs_context_suser(vfs_context_t ctx)
1245 {
1246 	return suser(ctx->vc_ucred, NULL);
1247 }
1248 
1249 /*
1250  * Return bit field of signals posted to all threads in the context's process.
1251  *
1252  * XXX Signals should be tied to threads, not processes, for most uses of this
1253  * XXX call.
1254  */
1255 int
vfs_context_issignal(vfs_context_t ctx,sigset_t mask)1256 vfs_context_issignal(vfs_context_t ctx, sigset_t mask)
1257 {
1258 	proc_t p = vfs_context_proc(ctx);
1259 	if (p) {
1260 		return proc_pendingsignals(p, mask);
1261 	}
1262 	return 0;
1263 }
1264 
1265 int
vfs_context_is64bit(vfs_context_t ctx)1266 vfs_context_is64bit(vfs_context_t ctx)
1267 {
1268 	uthread_t uth;
1269 
1270 	if (ctx != NULL && ctx->vc_thread != NULL) {
1271 		uth = get_bsdthread_info(ctx->vc_thread);
1272 	} else {
1273 		uth = current_uthread();
1274 	}
1275 	return uthread_is64bit(uth);
1276 }
1277 
1278 boolean_t
vfs_context_can_resolve_triggers(vfs_context_t ctx)1279 vfs_context_can_resolve_triggers(vfs_context_t ctx)
1280 {
1281 	proc_t proc = vfs_context_proc(ctx);
1282 
1283 	if (proc) {
1284 		if (proc->p_vfs_iopolicy &
1285 		    P_VFS_IOPOLICY_TRIGGER_RESOLVE_DISABLE) {
1286 			return false;
1287 		}
1288 		return true;
1289 	}
1290 	return false;
1291 }
1292 
1293 /*
1294  * vfs_context_proc
1295  *
1296  * Description:	Given a vfs_context_t, return the proc_t associated with it.
1297  *
1298  * Parameters:	vfs_context_t			The context to use
1299  *
1300  * Returns:	proc_t				The process for this context
1301  *
1302  * Notes:	This function will return the current_proc() if any of the
1303  *		following conditions are true:
1304  *
1305  *		o	The supplied context pointer is NULL
1306  *		o	There is no Mach thread associated with the context
1307  *		o	There is no Mach task associated with the Mach thread
1308  *		o	There is no proc_t associated with the Mach task
1309  *		o	The proc_t has no per process open file table
1310  *
1311  *		This causes this function to return a value matching as
1312  *		closely as possible the previous behaviour.
1313  */
1314 proc_t
vfs_context_proc(vfs_context_t ctx)1315 vfs_context_proc(vfs_context_t ctx)
1316 {
1317 	proc_t  proc = NULL;
1318 
1319 	if (ctx != NULL && ctx->vc_thread != NULL) {
1320 		proc = (proc_t)get_bsdthreadtask_info(ctx->vc_thread);
1321 	}
1322 
1323 	return proc == NULL ? current_proc() : proc;
1324 }
1325 
1326 /*
1327  * vfs_context_get_special_port
1328  *
1329  * Description: Return the requested special port from the task associated
1330  *              with the given context.
1331  *
1332  * Parameters:	vfs_context_t			The context to use
1333  *              int				Index of special port
1334  *              ipc_port_t *			Pointer to returned port
1335  *
1336  * Returns:	kern_return_t			see task_get_special_port()
1337  */
1338 kern_return_t
vfs_context_get_special_port(vfs_context_t ctx,int which,ipc_port_t * portp)1339 vfs_context_get_special_port(vfs_context_t ctx, int which, ipc_port_t *portp)
1340 {
1341 	task_t                  task = NULL;
1342 
1343 	if (ctx != NULL && ctx->vc_thread != NULL) {
1344 		task = get_threadtask(ctx->vc_thread);
1345 	}
1346 
1347 	return task_get_special_port(task, which, portp);
1348 }
1349 
1350 /*
1351  * vfs_context_set_special_port
1352  *
1353  * Description: Set the requested special port in the task associated
1354  *              with the given context.
1355  *
1356  * Parameters:	vfs_context_t			The context to use
1357  *              int				Index of special port
1358  *              ipc_port_t			New special port
1359  *
1360  * Returns:	kern_return_t			see task_set_special_port_internal()
1361  */
1362 kern_return_t
vfs_context_set_special_port(vfs_context_t ctx,int which,ipc_port_t port)1363 vfs_context_set_special_port(vfs_context_t ctx, int which, ipc_port_t port)
1364 {
1365 	task_t                  task = NULL;
1366 
1367 	if (ctx != NULL && ctx->vc_thread != NULL) {
1368 		task = get_threadtask(ctx->vc_thread);
1369 	}
1370 
1371 	return task_set_special_port_internal(task, which, port);
1372 }
1373 
1374 /*
1375  * vfs_context_thread
1376  *
1377  * Description:	Return the Mach thread associated with a vfs_context_t
1378  *
1379  * Parameters:	vfs_context_t			The context to use
1380  *
1381  * Returns:	thread_t			The thread for this context, or
1382  *						NULL, if there is not one.
1383  *
1384  * Notes:	NULL thread_t's are legal, but discouraged.  They occur only
1385  *		as a result of a static vfs_context_t declaration in a function
1386  *		and will result in this function returning NULL.
1387  *
1388  *		This is intentional; this function should NOT return the
1389  *		current_thread() in this case.
1390  */
1391 thread_t
vfs_context_thread(vfs_context_t ctx)1392 vfs_context_thread(vfs_context_t ctx)
1393 {
1394 	return ctx->vc_thread;
1395 }
1396 
1397 
1398 /*
1399  * vfs_context_cwd
1400  *
1401  * Description:	Returns a reference on the vnode for the current working
1402  *		directory for the supplied context
1403  *
1404  * Parameters:	vfs_context_t			The context to use
1405  *
1406  * Returns:	vnode_t				The current working directory
1407  *						for this context
1408  *
1409  * Notes:	The function first attempts to obtain the current directory
1410  *		from the thread, and if it is not present there, falls back
1411  *		to obtaining it from the process instead.  If it can't be
1412  *		obtained from either place, we return NULLVP.
1413  */
1414 vnode_t
vfs_context_cwd(vfs_context_t ctx)1415 vfs_context_cwd(vfs_context_t ctx)
1416 {
1417 	vnode_t cwd = NULLVP;
1418 
1419 	if (ctx != NULL && ctx->vc_thread != NULL) {
1420 		uthread_t uth = get_bsdthread_info(ctx->vc_thread);
1421 		proc_t proc;
1422 
1423 		/*
1424 		 * Get the cwd from the thread; if there isn't one, get it
1425 		 * from the process, instead.
1426 		 */
1427 		if ((cwd = uth->uu_cdir) == NULLVP &&
1428 		    (proc = (proc_t)get_bsdthreadtask_info(ctx->vc_thread)) != NULL) {
1429 			cwd = proc->p_fd.fd_cdir;
1430 		}
1431 	}
1432 
1433 	return cwd;
1434 }
1435 
1436 /*
1437  * vfs_context_create
1438  *
1439  * Description: Allocate and initialize a new context.
1440  *
1441  * Parameters:  vfs_context_t:                  Context to copy, or NULL for new
1442  *
1443  * Returns:     Pointer to new context
1444  *
1445  * Notes:       Copy cred and thread from argument, if available; else
1446  *              initialize with current thread and new cred.  Returns
1447  *              with a reference held on the credential.
1448  */
1449 vfs_context_t
vfs_context_create(vfs_context_t ctx)1450 vfs_context_create(vfs_context_t ctx)
1451 {
1452 	vfs_context_t newcontext;
1453 
1454 	newcontext = zalloc_flags(KT_VFS_CONTEXT, Z_WAITOK | Z_ZERO | Z_NOFAIL);
1455 
1456 	if (ctx == NULL) {
1457 		ctx = vfs_context_current();
1458 	}
1459 	*newcontext = *ctx;
1460 	if (IS_VALID_CRED(ctx->vc_ucred)) {
1461 		kauth_cred_ref(ctx->vc_ucred);
1462 	}
1463 
1464 	return newcontext;
1465 }
1466 
1467 
1468 vfs_context_t
vfs_context_current(void)1469 vfs_context_current(void)
1470 {
1471 	static_assert(offsetof(struct thread_ro, tro_owner) ==
1472 	    offsetof(struct vfs_context, vc_thread));
1473 	static_assert(offsetof(struct thread_ro, tro_cred) ==
1474 	    offsetof(struct vfs_context, vc_ucred));
1475 
1476 	return (vfs_context_t)current_thread_ro();
1477 }
1478 
1479 vfs_context_t
vfs_context_kernel(void)1480 vfs_context_kernel(void)
1481 {
1482 	return &vfs_context0;
1483 }
1484 
1485 int
vfs_context_rele(vfs_context_t ctx)1486 vfs_context_rele(vfs_context_t ctx)
1487 {
1488 	if (ctx) {
1489 		if (IS_VALID_CRED(ctx->vc_ucred)) {
1490 			kauth_cred_unref(&ctx->vc_ucred);
1491 		}
1492 		zfree(KT_VFS_CONTEXT, ctx);
1493 	}
1494 	return 0;
1495 }
1496 
1497 
1498 kauth_cred_t
vfs_context_ucred(vfs_context_t ctx)1499 vfs_context_ucred(vfs_context_t ctx)
1500 {
1501 	return ctx->vc_ucred;
1502 }
1503 
1504 /*
1505  * Return true if the context is owned by the superuser.
1506  */
1507 int
vfs_context_issuser(vfs_context_t ctx)1508 vfs_context_issuser(vfs_context_t ctx)
1509 {
1510 	return kauth_cred_issuser(vfs_context_ucred(ctx));
1511 }
1512 
1513 int
vfs_context_iskernel(vfs_context_t ctx)1514 vfs_context_iskernel(vfs_context_t ctx)
1515 {
1516 	return ctx == &vfs_context0;
1517 }
1518 
1519 /*
1520  * Given a context, for all fields of vfs_context_t which
1521  * are not held with a reference, set those fields to the
1522  * values for the current execution context.  Currently, this
1523  * just means the vc_thread.
1524  *
1525  * Returns: 0 for success, nonzero for failure
1526  *
1527  * The intended use is:
1528  * 1. vfs_context_create()	gets the caller a context
1529  * 2. vfs_context_bind()        sets the unrefcounted data
1530  * 3. vfs_context_rele()        releases the context
1531  *
1532  */
1533 int
vfs_context_bind(vfs_context_t ctx)1534 vfs_context_bind(vfs_context_t ctx)
1535 {
1536 	ctx->vc_thread = current_thread();
1537 	return 0;
1538 }
1539 
1540 int
vfs_set_thread_fs_private(uint8_t tag,uint64_t fs_private)1541 vfs_set_thread_fs_private(uint8_t tag, uint64_t fs_private)
1542 {
1543 	struct uthread *ut;
1544 
1545 	if (tag != FS_PRIVATE_TAG_APFS) {
1546 		return ENOTSUP;
1547 	}
1548 
1549 	ut = current_uthread();
1550 	ut->t_fs_private = fs_private;
1551 
1552 	return 0;
1553 }
1554 
1555 int
vfs_get_thread_fs_private(uint8_t tag,uint64_t * fs_private)1556 vfs_get_thread_fs_private(uint8_t tag, uint64_t *fs_private)
1557 {
1558 	struct uthread *ut;
1559 
1560 	if (tag != FS_PRIVATE_TAG_APFS) {
1561 		return ENOTSUP;
1562 	}
1563 
1564 	ut = current_uthread();
1565 	*fs_private = ut->t_fs_private;
1566 
1567 	return 0;
1568 }
1569 
1570 int
vfs_isswapmount(mount_t mnt)1571 vfs_isswapmount(mount_t mnt)
1572 {
1573 	return mnt && ISSET(mnt->mnt_kern_flag, MNTK_SWAP_MOUNT) ? 1 : 0;
1574 }
1575 
1576 /* XXXXXXXXXXXXXX VNODE KAPIS XXXXXXXXXXXXXXXXXXXXXXXXX */
1577 
1578 
1579 /*
1580  * Convert between vnode types and inode formats (since POSIX.1
1581  * defines mode word of stat structure in terms of inode formats).
1582  */
1583 enum vtype
vnode_iftovt(int mode)1584 vnode_iftovt(int mode)
1585 {
1586 	return iftovt_tab[((mode) & S_IFMT) >> 12];
1587 }
1588 
1589 int
vnode_vttoif(enum vtype indx)1590 vnode_vttoif(enum vtype indx)
1591 {
1592 	return vttoif_tab[(int)(indx)];
1593 }
1594 
1595 int
vnode_makeimode(int indx,int mode)1596 vnode_makeimode(int indx, int mode)
1597 {
1598 	return (int)(VTTOIF(indx) | (mode));
1599 }
1600 
1601 
1602 /*
1603  * vnode manipulation functions.
1604  */
1605 
1606 /* returns system root vnode iocount; It should be released using vnode_put() */
1607 vnode_t
vfs_rootvnode(void)1608 vfs_rootvnode(void)
1609 {
1610 	vnode_t vp = NULLVP;
1611 
1612 	if (rootvnode) {
1613 		lck_rw_lock_shared(&rootvnode_rw_lock);
1614 		vp = rootvnode;
1615 		if (vp && (vnode_get(vp) != 0)) {
1616 			vp = NULLVP;
1617 		}
1618 		lck_rw_unlock_shared(&rootvnode_rw_lock);
1619 	}
1620 
1621 	return vp;
1622 }
1623 
1624 uint32_t
vnode_vid(vnode_t vp)1625 vnode_vid(vnode_t vp)
1626 {
1627 	return (uint32_t)(vp->v_id);
1628 }
1629 
1630 mount_t
vnode_mount(vnode_t vp)1631 vnode_mount(vnode_t vp)
1632 {
1633 	return vp->v_mount;
1634 }
1635 
1636 #if CONFIG_IOSCHED
1637 vnode_t
vnode_mountdevvp(vnode_t vp)1638 vnode_mountdevvp(vnode_t vp)
1639 {
1640 	if (vp->v_mount) {
1641 		return vp->v_mount->mnt_devvp;
1642 	} else {
1643 		return (vnode_t)0;
1644 	}
1645 }
1646 #endif
1647 
1648 boolean_t
vnode_isonexternalstorage(vnode_t vp)1649 vnode_isonexternalstorage(vnode_t vp)
1650 {
1651 	if (vp) {
1652 		if (vp->v_mount) {
1653 			if (vp->v_mount->mnt_ioflags & MNT_IOFLAGS_PERIPHERAL_DRIVE) {
1654 				return TRUE;
1655 			}
1656 		}
1657 	}
1658 	return FALSE;
1659 }
1660 
1661 mount_t
vnode_mountedhere(vnode_t vp)1662 vnode_mountedhere(vnode_t vp)
1663 {
1664 	mount_t mp;
1665 
1666 	if ((vp->v_type == VDIR) && ((mp = vp->v_mountedhere) != NULL) &&
1667 	    (mp->mnt_vnodecovered == vp)) {
1668 		return mp;
1669 	} else {
1670 		return (mount_t)NULL;
1671 	}
1672 }
1673 
1674 /* returns vnode type of vnode_t */
1675 enum vtype
vnode_vtype(vnode_t vp)1676 vnode_vtype(vnode_t vp)
1677 {
1678 	return vp->v_type;
1679 }
1680 
1681 /* returns FS specific node saved in vnode */
1682 void *
vnode_fsnode(vnode_t vp)1683 vnode_fsnode(vnode_t vp)
1684 {
1685 	return vp->v_data;
1686 }
1687 
1688 void
vnode_clearfsnode(vnode_t vp)1689 vnode_clearfsnode(vnode_t vp)
1690 {
1691 	vp->v_data = NULL;
1692 }
1693 
1694 dev_t
vnode_specrdev(vnode_t vp)1695 vnode_specrdev(vnode_t vp)
1696 {
1697 	return vp->v_rdev;
1698 }
1699 
1700 
1701 /* Accessor functions */
1702 /* is vnode_t a root vnode */
1703 int
vnode_isvroot(vnode_t vp)1704 vnode_isvroot(vnode_t vp)
1705 {
1706 	return (vp->v_flag & VROOT)? 1 : 0;
1707 }
1708 
1709 /* is vnode_t a system vnode */
1710 int
vnode_issystem(vnode_t vp)1711 vnode_issystem(vnode_t vp)
1712 {
1713 	return (vp->v_flag & VSYSTEM)? 1 : 0;
1714 }
1715 
1716 /* is vnode_t a swap file vnode */
1717 int
vnode_isswap(vnode_t vp)1718 vnode_isswap(vnode_t vp)
1719 {
1720 	return (vp->v_flag & VSWAP)? 1 : 0;
1721 }
1722 
1723 /* is vnode_t a tty */
1724 int
vnode_istty(vnode_t vp)1725 vnode_istty(vnode_t vp)
1726 {
1727 	return (vp->v_flag & VISTTY) ? 1 : 0;
1728 }
1729 
1730 /* if vnode_t mount operation in progress */
1731 int
vnode_ismount(vnode_t vp)1732 vnode_ismount(vnode_t vp)
1733 {
1734 	return (vp->v_flag & VMOUNT)? 1 : 0;
1735 }
1736 
1737 /* is this vnode under recyle now */
1738 int
vnode_isrecycled(vnode_t vp)1739 vnode_isrecycled(vnode_t vp)
1740 {
1741 	int ret;
1742 
1743 	vnode_lock_spin(vp);
1744 	ret =  (vp->v_lflag & (VL_TERMINATE | VL_DEAD))? 1 : 0;
1745 	vnode_unlock(vp);
1746 	return ret;
1747 }
1748 
1749 /* is this vnode marked for termination */
1750 int
vnode_willberecycled(vnode_t vp)1751 vnode_willberecycled(vnode_t vp)
1752 {
1753 	return (vp->v_lflag & VL_MARKTERM) ? 1 : 0;
1754 }
1755 
1756 
1757 /* vnode was created by background task requesting rapid aging
1758  *  and has not since been referenced by a normal task */
1759 int
vnode_israge(vnode_t vp)1760 vnode_israge(vnode_t vp)
1761 {
1762 	return (vp->v_flag & VRAGE)? 1 : 0;
1763 }
1764 
1765 int
vnode_needssnapshots(vnode_t vp)1766 vnode_needssnapshots(vnode_t vp)
1767 {
1768 	return (vp->v_flag & VNEEDSSNAPSHOT)? 1 : 0;
1769 }
1770 
1771 
1772 /* Check the process/thread to see if we should skip atime updates */
1773 int
vfs_ctx_skipatime(vfs_context_t ctx)1774 vfs_ctx_skipatime(vfs_context_t ctx)
1775 {
1776 	struct uthread *ut;
1777 	proc_t proc;
1778 	thread_t thr;
1779 
1780 	proc = vfs_context_proc(ctx);
1781 	thr = vfs_context_thread(ctx);
1782 
1783 	/* Validate pointers in case we were invoked via a kernel context */
1784 	if (thr && proc) {
1785 		ut = get_bsdthread_info(thr);
1786 
1787 		if (proc->p_lflag & P_LRAGE_VNODES) {
1788 			return 1;
1789 		}
1790 
1791 		if (ut) {
1792 			if (ut->uu_flag & (UT_RAGE_VNODES | UT_ATIME_UPDATE)) {
1793 				return 1;
1794 			}
1795 		}
1796 
1797 		if (proc->p_vfs_iopolicy & P_VFS_IOPOLICY_ATIME_UPDATES) {
1798 			return 1;
1799 		}
1800 	}
1801 	return 0;
1802 }
1803 
1804 /* is vnode_t marked to not keep data cached once it's been consumed */
1805 int
vnode_isnocache(vnode_t vp)1806 vnode_isnocache(vnode_t vp)
1807 {
1808 	return (vp->v_flag & VNOCACHE_DATA)? 1 : 0;
1809 }
1810 
1811 /*
1812  * has sequential readahead been disabled on this vnode
1813  */
1814 int
vnode_isnoreadahead(vnode_t vp)1815 vnode_isnoreadahead(vnode_t vp)
1816 {
1817 	return (vp->v_flag & VRAOFF)? 1 : 0;
1818 }
1819 
1820 int
vnode_is_openevt(vnode_t vp)1821 vnode_is_openevt(vnode_t vp)
1822 {
1823 	return (vp->v_flag & VOPENEVT)? 1 : 0;
1824 }
1825 
1826 /* is vnode_t a standard one? */
1827 int
vnode_isstandard(vnode_t vp)1828 vnode_isstandard(vnode_t vp)
1829 {
1830 	return (vp->v_flag & VSTANDARD)? 1 : 0;
1831 }
1832 
1833 /* don't vflush() if SKIPSYSTEM */
1834 int
vnode_isnoflush(vnode_t vp)1835 vnode_isnoflush(vnode_t vp)
1836 {
1837 	return (vp->v_flag & VNOFLUSH)? 1 : 0;
1838 }
1839 
1840 /* is vnode_t a regular file */
1841 int
vnode_isreg(vnode_t vp)1842 vnode_isreg(vnode_t vp)
1843 {
1844 	return (vp->v_type == VREG)? 1 : 0;
1845 }
1846 
1847 /* is vnode_t a directory? */
1848 int
vnode_isdir(vnode_t vp)1849 vnode_isdir(vnode_t vp)
1850 {
1851 	return (vp->v_type == VDIR)? 1 : 0;
1852 }
1853 
1854 /* is vnode_t a symbolic link ? */
1855 int
vnode_islnk(vnode_t vp)1856 vnode_islnk(vnode_t vp)
1857 {
1858 	return (vp->v_type == VLNK)? 1 : 0;
1859 }
1860 
1861 int
vnode_lookup_continue_needed(vnode_t vp,struct componentname * cnp)1862 vnode_lookup_continue_needed(vnode_t vp, struct componentname *cnp)
1863 {
1864 	struct nameidata *ndp = cnp->cn_ndp;
1865 
1866 	if (ndp == NULL) {
1867 		panic("vnode_lookup_continue_needed(): cnp->cn_ndp is NULL");
1868 	}
1869 
1870 	if (vnode_isdir(vp)) {
1871 		if (vp->v_mountedhere != NULL) {
1872 			goto yes;
1873 		}
1874 
1875 #if CONFIG_TRIGGERS
1876 		if (vp->v_resolve) {
1877 			goto yes;
1878 		}
1879 #endif /* CONFIG_TRIGGERS */
1880 	}
1881 
1882 
1883 	if (vnode_islnk(vp)) {
1884 		/* From lookup():  || *ndp->ni_next == '/') No need for this, we know we're NULL-terminated here */
1885 		if (cnp->cn_flags & FOLLOW) {
1886 			goto yes;
1887 		}
1888 		if (ndp->ni_flag & NAMEI_TRAILINGSLASH) {
1889 			goto yes;
1890 		}
1891 	}
1892 
1893 	return 0;
1894 
1895 yes:
1896 	ndp->ni_flag |= NAMEI_CONTLOOKUP;
1897 	return EKEEPLOOKING;
1898 }
1899 
1900 /* is vnode_t a fifo ? */
1901 int
vnode_isfifo(vnode_t vp)1902 vnode_isfifo(vnode_t vp)
1903 {
1904 	return (vp->v_type == VFIFO)? 1 : 0;
1905 }
1906 
1907 /* is vnode_t a block device? */
1908 int
vnode_isblk(vnode_t vp)1909 vnode_isblk(vnode_t vp)
1910 {
1911 	return (vp->v_type == VBLK)? 1 : 0;
1912 }
1913 
1914 int
vnode_isspec(vnode_t vp)1915 vnode_isspec(vnode_t vp)
1916 {
1917 	return ((vp->v_type == VCHR) || (vp->v_type == VBLK)) ? 1 : 0;
1918 }
1919 
1920 /* is vnode_t a char device? */
1921 int
vnode_ischr(vnode_t vp)1922 vnode_ischr(vnode_t vp)
1923 {
1924 	return (vp->v_type == VCHR)? 1 : 0;
1925 }
1926 
1927 /* is vnode_t a socket? */
1928 int
vnode_issock(vnode_t vp)1929 vnode_issock(vnode_t vp)
1930 {
1931 	return (vp->v_type == VSOCK)? 1 : 0;
1932 }
1933 
1934 /* is vnode_t a device with multiple active vnodes referring to it? */
1935 int
vnode_isaliased(vnode_t vp)1936 vnode_isaliased(vnode_t vp)
1937 {
1938 	enum vtype vt = vp->v_type;
1939 	if (!((vt == VCHR) || (vt == VBLK))) {
1940 		return 0;
1941 	} else {
1942 		return vp->v_specflags & SI_ALIASED;
1943 	}
1944 }
1945 
1946 /* is vnode_t a named stream? */
1947 int
vnode_isnamedstream(vnode_t vp)1948 vnode_isnamedstream(
1949 #if NAMEDSTREAMS
1950 	vnode_t vp
1951 #else
1952 	__unused vnode_t vp
1953 #endif
1954 	)
1955 {
1956 #if NAMEDSTREAMS
1957 	return (vp->v_flag & VISNAMEDSTREAM) ? 1 : 0;
1958 #else
1959 	return 0;
1960 #endif
1961 }
1962 
1963 int
vnode_isshadow(vnode_t vp)1964 vnode_isshadow(
1965 #if NAMEDSTREAMS
1966 	vnode_t vp
1967 #else
1968 	__unused vnode_t vp
1969 #endif
1970 	)
1971 {
1972 #if NAMEDSTREAMS
1973 	return (vp->v_flag & VISSHADOW) ? 1 : 0;
1974 #else
1975 	return 0;
1976 #endif
1977 }
1978 
1979 /* does vnode have associated named stream vnodes ? */
1980 int
vnode_hasnamedstreams(vnode_t vp)1981 vnode_hasnamedstreams(
1982 #if NAMEDSTREAMS
1983 	vnode_t vp
1984 #else
1985 	__unused vnode_t vp
1986 #endif
1987 	)
1988 {
1989 #if NAMEDSTREAMS
1990 	return (vp->v_lflag & VL_HASSTREAMS) ? 1 : 0;
1991 #else
1992 	return 0;
1993 #endif
1994 }
1995 /* TBD:  set vnode_t to not cache data after it is consumed once; used for quota */
1996 void
vnode_setnocache(vnode_t vp)1997 vnode_setnocache(vnode_t vp)
1998 {
1999 	vnode_lock_spin(vp);
2000 	vp->v_flag |= VNOCACHE_DATA;
2001 	vnode_unlock(vp);
2002 }
2003 
2004 void
vnode_clearnocache(vnode_t vp)2005 vnode_clearnocache(vnode_t vp)
2006 {
2007 	vnode_lock_spin(vp);
2008 	vp->v_flag &= ~VNOCACHE_DATA;
2009 	vnode_unlock(vp);
2010 }
2011 
2012 void
vnode_set_openevt(vnode_t vp)2013 vnode_set_openevt(vnode_t vp)
2014 {
2015 	vnode_lock_spin(vp);
2016 	vp->v_flag |= VOPENEVT;
2017 	vnode_unlock(vp);
2018 }
2019 
2020 void
vnode_clear_openevt(vnode_t vp)2021 vnode_clear_openevt(vnode_t vp)
2022 {
2023 	vnode_lock_spin(vp);
2024 	vp->v_flag &= ~VOPENEVT;
2025 	vnode_unlock(vp);
2026 }
2027 
2028 
2029 void
vnode_setnoreadahead(vnode_t vp)2030 vnode_setnoreadahead(vnode_t vp)
2031 {
2032 	vnode_lock_spin(vp);
2033 	vp->v_flag |= VRAOFF;
2034 	vnode_unlock(vp);
2035 }
2036 
2037 void
vnode_clearnoreadahead(vnode_t vp)2038 vnode_clearnoreadahead(vnode_t vp)
2039 {
2040 	vnode_lock_spin(vp);
2041 	vp->v_flag &= ~VRAOFF;
2042 	vnode_unlock(vp);
2043 }
2044 
2045 int
vnode_isfastdevicecandidate(vnode_t vp)2046 vnode_isfastdevicecandidate(vnode_t vp)
2047 {
2048 	return (vp->v_flag & VFASTDEVCANDIDATE)? 1 : 0;
2049 }
2050 
2051 void
vnode_setfastdevicecandidate(vnode_t vp)2052 vnode_setfastdevicecandidate(vnode_t vp)
2053 {
2054 	vnode_lock_spin(vp);
2055 	vp->v_flag |= VFASTDEVCANDIDATE;
2056 	vnode_unlock(vp);
2057 }
2058 
2059 void
vnode_clearfastdevicecandidate(vnode_t vp)2060 vnode_clearfastdevicecandidate(vnode_t vp)
2061 {
2062 	vnode_lock_spin(vp);
2063 	vp->v_flag &= ~VFASTDEVCANDIDATE;
2064 	vnode_unlock(vp);
2065 }
2066 
2067 int
vnode_isautocandidate(vnode_t vp)2068 vnode_isautocandidate(vnode_t vp)
2069 {
2070 	return (vp->v_flag & VAUTOCANDIDATE)? 1 : 0;
2071 }
2072 
2073 void
vnode_setautocandidate(vnode_t vp)2074 vnode_setautocandidate(vnode_t vp)
2075 {
2076 	vnode_lock_spin(vp);
2077 	vp->v_flag |= VAUTOCANDIDATE;
2078 	vnode_unlock(vp);
2079 }
2080 
2081 void
vnode_clearautocandidate(vnode_t vp)2082 vnode_clearautocandidate(vnode_t vp)
2083 {
2084 	vnode_lock_spin(vp);
2085 	vp->v_flag &= ~VAUTOCANDIDATE;
2086 	vnode_unlock(vp);
2087 }
2088 
2089 
2090 
2091 
2092 /* mark vnode_t to skip vflush() is SKIPSYSTEM */
2093 void
vnode_setnoflush(vnode_t vp)2094 vnode_setnoflush(vnode_t vp)
2095 {
2096 	vnode_lock_spin(vp);
2097 	vp->v_flag |= VNOFLUSH;
2098 	vnode_unlock(vp);
2099 }
2100 
2101 void
vnode_clearnoflush(vnode_t vp)2102 vnode_clearnoflush(vnode_t vp)
2103 {
2104 	vnode_lock_spin(vp);
2105 	vp->v_flag &= ~VNOFLUSH;
2106 	vnode_unlock(vp);
2107 }
2108 
2109 
2110 /* is vnode_t a blkdevice and has a FS mounted on it */
2111 int
vnode_ismountedon(vnode_t vp)2112 vnode_ismountedon(vnode_t vp)
2113 {
2114 	return (vp->v_specflags & SI_MOUNTEDON)? 1 : 0;
2115 }
2116 
2117 void
vnode_setmountedon(vnode_t vp)2118 vnode_setmountedon(vnode_t vp)
2119 {
2120 	vnode_lock_spin(vp);
2121 	vp->v_specflags |= SI_MOUNTEDON;
2122 	vnode_unlock(vp);
2123 }
2124 
2125 void
vnode_clearmountedon(vnode_t vp)2126 vnode_clearmountedon(vnode_t vp)
2127 {
2128 	vnode_lock_spin(vp);
2129 	vp->v_specflags &= ~SI_MOUNTEDON;
2130 	vnode_unlock(vp);
2131 }
2132 
2133 
2134 void
vnode_settag(vnode_t vp,int tag)2135 vnode_settag(vnode_t vp, int tag)
2136 {
2137 	/*
2138 	 * We only assign enum values to v_tag, but add an assert to make sure we
2139 	 * catch it in dev/debug builds if this ever change.
2140 	 */
2141 	assert(tag >= SHRT_MIN && tag <= SHRT_MAX);
2142 	vp->v_tag = (uint16_t)tag;
2143 }
2144 
2145 int
vnode_tag(vnode_t vp)2146 vnode_tag(vnode_t vp)
2147 {
2148 	return vp->v_tag;
2149 }
2150 
2151 vnode_t
vnode_parent(vnode_t vp)2152 vnode_parent(vnode_t vp)
2153 {
2154 	return vp->v_parent;
2155 }
2156 
2157 void
vnode_setparent(vnode_t vp,vnode_t dvp)2158 vnode_setparent(vnode_t vp, vnode_t dvp)
2159 {
2160 	vp->v_parent = dvp;
2161 }
2162 
2163 void
vnode_setname(vnode_t vp,char * name)2164 vnode_setname(vnode_t vp, char * name)
2165 {
2166 	vp->v_name = name;
2167 }
2168 
2169 /* return the registered  FS name when adding the FS to kernel */
2170 void
vnode_vfsname(vnode_t vp,char * buf)2171 vnode_vfsname(vnode_t vp, char * buf)
2172 {
2173 	strlcpy(buf, vp->v_mount->mnt_vtable->vfc_name, MFSNAMELEN);
2174 }
2175 
2176 /* return the FS type number */
2177 int
vnode_vfstypenum(vnode_t vp)2178 vnode_vfstypenum(vnode_t vp)
2179 {
2180 	return vp->v_mount->mnt_vtable->vfc_typenum;
2181 }
2182 
2183 int
vnode_vfs64bitready(vnode_t vp)2184 vnode_vfs64bitready(vnode_t vp)
2185 {
2186 	/*
2187 	 * Checking for dead_mountp is a bit of a hack for SnowLeopard: <rdar://problem/6269051>
2188 	 */
2189 	if ((vp->v_mount != dead_mountp) && (vp->v_mount->mnt_vtable->vfc_vfsflags & VFC_VFS64BITREADY)) {
2190 		return 1;
2191 	} else {
2192 		return 0;
2193 	}
2194 }
2195 
2196 
2197 
2198 /* return the visible flags on associated mount point of vnode_t */
2199 uint32_t
vnode_vfsvisflags(vnode_t vp)2200 vnode_vfsvisflags(vnode_t vp)
2201 {
2202 	return vp->v_mount->mnt_flag & MNT_VISFLAGMASK;
2203 }
2204 
2205 /* return the command modifier flags on associated mount point of vnode_t */
2206 uint32_t
vnode_vfscmdflags(vnode_t vp)2207 vnode_vfscmdflags(vnode_t vp)
2208 {
2209 	return vp->v_mount->mnt_flag & MNT_CMDFLAGS;
2210 }
2211 
2212 /* return the max symlink of short links  of vnode_t */
2213 uint32_t
vnode_vfsmaxsymlen(vnode_t vp)2214 vnode_vfsmaxsymlen(vnode_t vp)
2215 {
2216 	return vp->v_mount->mnt_maxsymlinklen;
2217 }
2218 
2219 /* return a pointer to the RO vfs_statfs associated with vnode_t's mount point */
2220 struct vfsstatfs *
vnode_vfsstatfs(vnode_t vp)2221 vnode_vfsstatfs(vnode_t vp)
2222 {
2223 	return &vp->v_mount->mnt_vfsstat;
2224 }
2225 
2226 /* return a handle to the FSs specific private handle associated with vnode_t's mount point */
2227 void *
vnode_vfsfsprivate(vnode_t vp)2228 vnode_vfsfsprivate(vnode_t vp)
2229 {
2230 	return vp->v_mount->mnt_data;
2231 }
2232 
2233 /* is vnode_t in a rdonly mounted  FS */
2234 int
vnode_vfsisrdonly(vnode_t vp)2235 vnode_vfsisrdonly(vnode_t vp)
2236 {
2237 	return (vp->v_mount->mnt_flag & MNT_RDONLY)? 1 : 0;
2238 }
2239 
2240 int
vnode_compound_rename_available(vnode_t vp)2241 vnode_compound_rename_available(vnode_t vp)
2242 {
2243 	return vnode_compound_op_available(vp, COMPOUND_VNOP_RENAME);
2244 }
2245 int
vnode_compound_rmdir_available(vnode_t vp)2246 vnode_compound_rmdir_available(vnode_t vp)
2247 {
2248 	return vnode_compound_op_available(vp, COMPOUND_VNOP_RMDIR);
2249 }
2250 int
vnode_compound_mkdir_available(vnode_t vp)2251 vnode_compound_mkdir_available(vnode_t vp)
2252 {
2253 	return vnode_compound_op_available(vp, COMPOUND_VNOP_MKDIR);
2254 }
2255 int
vnode_compound_remove_available(vnode_t vp)2256 vnode_compound_remove_available(vnode_t vp)
2257 {
2258 	return vnode_compound_op_available(vp, COMPOUND_VNOP_REMOVE);
2259 }
2260 int
vnode_compound_open_available(vnode_t vp)2261 vnode_compound_open_available(vnode_t vp)
2262 {
2263 	return vnode_compound_op_available(vp, COMPOUND_VNOP_OPEN);
2264 }
2265 
2266 int
vnode_compound_op_available(vnode_t vp,compound_vnop_id_t opid)2267 vnode_compound_op_available(vnode_t vp, compound_vnop_id_t opid)
2268 {
2269 	return (vp->v_mount->mnt_compound_ops & opid) != 0;
2270 }
2271 
2272 /*
2273  * Returns vnode ref to current working directory; if a per-thread current
2274  * working directory is in effect, return that instead of the per process one.
2275  *
2276  * XXX Published, but not used.
2277  */
2278 vnode_t
current_workingdir(void)2279 current_workingdir(void)
2280 {
2281 	return vfs_context_cwd(vfs_context_current());
2282 }
2283 
2284 /*
2285  * Get a filesec and optional acl contents from an extended attribute.
2286  * Function will attempt to retrive ACL, UUID, and GUID information using a
2287  * read of a named extended attribute (KAUTH_FILESEC_XATTR).
2288  *
2289  * Parameters:	vp			The vnode on which to operate.
2290  *		fsecp			The filesec (and ACL, if any) being
2291  *					retrieved.
2292  *		ctx			The vnode context in which the
2293  *					operation is to be attempted.
2294  *
2295  * Returns:	0			Success
2296  *		!0			errno value
2297  *
2298  * Notes:	The kauth_filesec_t in '*fsecp', if retrieved, will be in
2299  *		host byte order, as will be the ACL contents, if any.
2300  *		Internally, we will cannonize these values from network (PPC)
2301  *		byte order after we retrieve them so that the on-disk contents
2302  *		of the extended attribute are identical for both PPC and Intel
2303  *		(if we were not being required to provide this service via
2304  *		fallback, this would be the job of the filesystem
2305  *		'VNOP_GETATTR' call).
2306  *
2307  *		We use ntohl() because it has a transitive property on Intel
2308  *		machines and no effect on PPC mancines.  This guarantees us
2309  *
2310  * XXX:		Deleting rather than ignoreing a corrupt security structure is
2311  *		probably the only way to reset it without assistance from an
2312  *		file system integrity checking tool.  Right now we ignore it.
2313  *
2314  * XXX:		We should enummerate the possible errno values here, and where
2315  *		in the code they originated.
2316  */
2317 static int
vnode_get_filesec(vnode_t vp,kauth_filesec_t * fsecp,vfs_context_t ctx)2318 vnode_get_filesec(vnode_t vp, kauth_filesec_t *fsecp, vfs_context_t ctx)
2319 {
2320 	kauth_filesec_t fsec;
2321 	uio_t   fsec_uio;
2322 	size_t  fsec_size;
2323 	size_t  xsize, rsize;
2324 	int     error;
2325 	uint32_t        host_fsec_magic;
2326 	uint32_t        host_acl_entrycount;
2327 
2328 	fsec = NULL;
2329 	fsec_uio = NULL;
2330 
2331 	/* find out how big the EA is */
2332 	error = vn_getxattr(vp, KAUTH_FILESEC_XATTR, NULL, &xsize, XATTR_NOSECURITY, ctx);
2333 	if (error != 0) {
2334 		/* no EA, no filesec */
2335 		if ((error == ENOATTR) || (error == ENOENT) || (error == EJUSTRETURN)) {
2336 			error = 0;
2337 		}
2338 		/* either way, we are done */
2339 		goto out;
2340 	}
2341 
2342 	/*
2343 	 * To be valid, a kauth_filesec_t must be large enough to hold a zero
2344 	 * ACE entrly ACL, and if it's larger than that, it must have the right
2345 	 * number of bytes such that it contains an atomic number of ACEs,
2346 	 * rather than partial entries.  Otherwise, we ignore it.
2347 	 */
2348 	if (!KAUTH_FILESEC_VALID(xsize)) {
2349 		KAUTH_DEBUG("    ERROR - Bogus kauth_fiilesec_t: %ld bytes", xsize);
2350 		error = 0;
2351 		goto out;
2352 	}
2353 
2354 	/* how many entries would fit? */
2355 	fsec_size = KAUTH_FILESEC_COUNT(xsize);
2356 	if (fsec_size > KAUTH_ACL_MAX_ENTRIES) {
2357 		KAUTH_DEBUG("    ERROR - Bogus (too large) kauth_fiilesec_t: %ld bytes", xsize);
2358 		error = 0;
2359 		goto out;
2360 	}
2361 
2362 	/* get buffer and uio */
2363 	if (((fsec = kauth_filesec_alloc((int)fsec_size)) == NULL) ||
2364 	    ((fsec_uio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ)) == NULL) ||
2365 	    uio_addiov(fsec_uio, CAST_USER_ADDR_T(fsec), xsize)) {
2366 		KAUTH_DEBUG("    ERROR - could not allocate iov to read ACL");
2367 		error = ENOMEM;
2368 		goto out;
2369 	}
2370 
2371 	/* read security attribute */
2372 	rsize = xsize;
2373 	if ((error = vn_getxattr(vp,
2374 	    KAUTH_FILESEC_XATTR,
2375 	    fsec_uio,
2376 	    &rsize,
2377 	    XATTR_NOSECURITY,
2378 	    ctx)) != 0) {
2379 		/* no attribute - no security data */
2380 		if ((error == ENOATTR) || (error == ENOENT) || (error == EJUSTRETURN)) {
2381 			error = 0;
2382 		}
2383 		/* either way, we are done */
2384 		goto out;
2385 	}
2386 
2387 	/*
2388 	 * Validate security structure; the validation must take place in host
2389 	 * byte order.  If it's corrupt, we will just ignore it.
2390 	 */
2391 
2392 	/* Validate the size before trying to convert it */
2393 	if (rsize < KAUTH_FILESEC_SIZE(0)) {
2394 		KAUTH_DEBUG("ACL - DATA TOO SMALL (%d)", rsize);
2395 		goto out;
2396 	}
2397 
2398 	/* Validate the magic number before trying to convert it */
2399 	host_fsec_magic = ntohl(KAUTH_FILESEC_MAGIC);
2400 	if (fsec->fsec_magic != host_fsec_magic) {
2401 		KAUTH_DEBUG("ACL - BAD MAGIC %x", host_fsec_magic);
2402 		goto out;
2403 	}
2404 
2405 	/* Validate the entry count before trying to convert it. */
2406 	host_acl_entrycount = ntohl(fsec->fsec_acl.acl_entrycount);
2407 	if (host_acl_entrycount != KAUTH_FILESEC_NOACL) {
2408 		if (host_acl_entrycount > KAUTH_ACL_MAX_ENTRIES) {
2409 			KAUTH_DEBUG("ACL - BAD ENTRYCOUNT %x", host_acl_entrycount);
2410 			goto out;
2411 		}
2412 		if (KAUTH_FILESEC_SIZE(host_acl_entrycount) > rsize) {
2413 			KAUTH_DEBUG("ACL - BUFFER OVERFLOW (%d entries too big for %d)", host_acl_entrycount, rsize);
2414 			goto out;
2415 		}
2416 	}
2417 
2418 	kauth_filesec_acl_setendian(KAUTH_ENDIAN_HOST, fsec, NULL);
2419 
2420 	*fsecp = fsec;
2421 	fsec = NULL;
2422 	error = 0;
2423 out:
2424 	if (fsec != NULL) {
2425 		kauth_filesec_free(fsec);
2426 	}
2427 	if (fsec_uio != NULL) {
2428 		uio_free(fsec_uio);
2429 	}
2430 	if (error) {
2431 		*fsecp = NULL;
2432 	}
2433 	return error;
2434 }
2435 
2436 /*
2437  * Set a filesec and optional acl contents into an extended attribute.
2438  * function will attempt to store ACL, UUID, and GUID information using a
2439  * write to a named extended attribute (KAUTH_FILESEC_XATTR).  The 'acl'
2440  * may or may not point to the `fsec->fsec_acl`, depending on whether the
2441  * original caller supplied an acl.
2442  *
2443  * Parameters:	vp			The vnode on which to operate.
2444  *		fsec			The filesec being set.
2445  *		acl			The acl to be associated with 'fsec'.
2446  *		ctx			The vnode context in which the
2447  *					operation is to be attempted.
2448  *
2449  * Returns:	0			Success
2450  *		!0			errno value
2451  *
2452  * Notes:	Both the fsec and the acl are always valid.
2453  *
2454  *		The kauth_filesec_t in 'fsec', if any, is in host byte order,
2455  *		as are the acl contents, if they are used.  Internally, we will
2456  *		cannonize these values into network (PPC) byte order before we
2457  *		attempt to write them so that the on-disk contents of the
2458  *		extended attribute are identical for both PPC and Intel (if we
2459  *		were not being required to provide this service via fallback,
2460  *		this would be the job of the filesystem 'VNOP_SETATTR' call).
2461  *		We reverse this process on the way out, so we leave with the
2462  *		same byte order we started with.
2463  *
2464  * XXX:		We should enummerate the possible errno values here, and where
2465  *		in the code they originated.
2466  */
2467 static int
vnode_set_filesec(vnode_t vp,kauth_filesec_t fsec,kauth_acl_t acl,vfs_context_t ctx)2468 vnode_set_filesec(vnode_t vp, kauth_filesec_t fsec, kauth_acl_t acl, vfs_context_t ctx)
2469 {
2470 	uio_t           fsec_uio;
2471 	int             error;
2472 	uint32_t        saved_acl_copysize;
2473 
2474 	fsec_uio = NULL;
2475 
2476 	if ((fsec_uio = uio_create(2, 0, UIO_SYSSPACE, UIO_WRITE)) == NULL) {
2477 		KAUTH_DEBUG("    ERROR - could not allocate iov to write ACL");
2478 		error = ENOMEM;
2479 		goto out;
2480 	}
2481 	/*
2482 	 * Save the pre-converted ACL copysize, because it gets swapped too
2483 	 * if we are running with the wrong endianness.
2484 	 */
2485 	saved_acl_copysize = KAUTH_ACL_COPYSIZE(acl);
2486 
2487 	kauth_filesec_acl_setendian(KAUTH_ENDIAN_DISK, fsec, acl);
2488 
2489 	uio_addiov(fsec_uio, CAST_USER_ADDR_T(fsec), KAUTH_FILESEC_SIZE(0) - KAUTH_ACL_SIZE(KAUTH_FILESEC_NOACL));
2490 	uio_addiov(fsec_uio, CAST_USER_ADDR_T(acl), saved_acl_copysize);
2491 	error = vn_setxattr(vp,
2492 	    KAUTH_FILESEC_XATTR,
2493 	    fsec_uio,
2494 	    XATTR_NOSECURITY,           /* we have auth'ed already */
2495 	    ctx);
2496 	VFS_DEBUG(ctx, vp, "SETATTR - set ACL returning %d", error);
2497 
2498 	kauth_filesec_acl_setendian(KAUTH_ENDIAN_HOST, fsec, acl);
2499 
2500 out:
2501 	if (fsec_uio != NULL) {
2502 		uio_free(fsec_uio);
2503 	}
2504 	return error;
2505 }
2506 
2507 /*
2508  * Handle uid/gid == 99 and MNT_IGNORE_OWNERSHIP here.
2509  */
2510 void
vnode_attr_handle_mnt_ignore_ownership(struct vnode_attr * vap,mount_t mp,vfs_context_t ctx)2511 vnode_attr_handle_mnt_ignore_ownership(struct vnode_attr *vap, mount_t mp, vfs_context_t ctx)
2512 {
2513 	uid_t   nuid;
2514 	gid_t   ngid;
2515 
2516 	if (VATTR_IS_ACTIVE(vap, va_uid)) {
2517 		if (vfs_context_issuser(ctx) && VATTR_IS_SUPPORTED(vap, va_uid)) {
2518 			nuid = vap->va_uid;
2519 		} else if (mp->mnt_flag & MNT_IGNORE_OWNERSHIP) {
2520 			nuid = mp->mnt_fsowner;
2521 			if (nuid == KAUTH_UID_NONE) {
2522 				nuid = 99;
2523 			}
2524 		} else if (VATTR_IS_SUPPORTED(vap, va_uid)) {
2525 			nuid = vap->va_uid;
2526 		} else {
2527 			/* this will always be something sensible */
2528 			nuid = mp->mnt_fsowner;
2529 		}
2530 		if ((nuid == 99) && !vfs_context_issuser(ctx)) {
2531 			nuid = kauth_cred_getuid(vfs_context_ucred(ctx));
2532 		}
2533 		VATTR_RETURN(vap, va_uid, nuid);
2534 	}
2535 	if (VATTR_IS_ACTIVE(vap, va_gid)) {
2536 		if (vfs_context_issuser(ctx) && VATTR_IS_SUPPORTED(vap, va_gid)) {
2537 			ngid = vap->va_gid;
2538 		} else if (mp->mnt_flag & MNT_IGNORE_OWNERSHIP) {
2539 			ngid = mp->mnt_fsgroup;
2540 			if (ngid == KAUTH_GID_NONE) {
2541 				ngid = 99;
2542 			}
2543 		} else if (VATTR_IS_SUPPORTED(vap, va_gid)) {
2544 			ngid = vap->va_gid;
2545 		} else {
2546 			/* this will always be something sensible */
2547 			ngid = mp->mnt_fsgroup;
2548 		}
2549 		if ((ngid == 99) && !vfs_context_issuser(ctx)) {
2550 			ngid = kauth_cred_getgid(vfs_context_ucred(ctx));
2551 		}
2552 		VATTR_RETURN(vap, va_gid, ngid);
2553 	}
2554 }
2555 
2556 /*
2557  * Returns:	0			Success
2558  *		ENOMEM			Not enough space [only if has filesec]
2559  *		EINVAL			Requested unknown attributes
2560  *		VNOP_GETATTR:		???
2561  *		vnode_get_filesec:	???
2562  *		kauth_cred_guid2uid:	???
2563  *		kauth_cred_guid2gid:	???
2564  *		vfs_update_vfsstat:	???
2565  */
2566 int
vnode_getattr(vnode_t vp,struct vnode_attr * vap,vfs_context_t ctx)2567 vnode_getattr(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)
2568 {
2569 	kauth_filesec_t fsec;
2570 	kauth_acl_t facl;
2571 	int     error;
2572 
2573 	/*
2574 	 * Reject attempts to fetch unknown attributes.
2575 	 */
2576 	if (vap->va_active & ~VNODE_ATTR_ALL) {
2577 		return EINVAL;
2578 	}
2579 
2580 	/* don't ask for extended security data if the filesystem doesn't support it */
2581 	if (!vfs_extendedsecurity(vnode_mount(vp))) {
2582 		VATTR_CLEAR_ACTIVE(vap, va_acl);
2583 		VATTR_CLEAR_ACTIVE(vap, va_uuuid);
2584 		VATTR_CLEAR_ACTIVE(vap, va_guuid);
2585 	}
2586 
2587 	/*
2588 	 * If the caller wants size values we might have to synthesise, give the
2589 	 * filesystem the opportunity to supply better intermediate results.
2590 	 */
2591 	if (VATTR_IS_ACTIVE(vap, va_data_alloc) ||
2592 	    VATTR_IS_ACTIVE(vap, va_total_size) ||
2593 	    VATTR_IS_ACTIVE(vap, va_total_alloc)) {
2594 		VATTR_SET_ACTIVE(vap, va_data_size);
2595 		VATTR_SET_ACTIVE(vap, va_data_alloc);
2596 		VATTR_SET_ACTIVE(vap, va_total_size);
2597 		VATTR_SET_ACTIVE(vap, va_total_alloc);
2598 	}
2599 
2600 	vap->va_vaflags &= ~VA_USEFSID;
2601 
2602 	error = VNOP_GETATTR(vp, vap, ctx);
2603 	if (error) {
2604 		KAUTH_DEBUG("ERROR - returning %d", error);
2605 		goto out;
2606 	}
2607 
2608 	/*
2609 	 * If extended security data was requested but not returned, try the fallback
2610 	 * path.
2611 	 */
2612 	if (VATTR_NOT_RETURNED(vap, va_acl) || VATTR_NOT_RETURNED(vap, va_uuuid) || VATTR_NOT_RETURNED(vap, va_guuid)) {
2613 		fsec = NULL;
2614 
2615 		if (XATTR_VNODE_SUPPORTED(vp)) {
2616 			/* try to get the filesec */
2617 			if ((error = vnode_get_filesec(vp, &fsec, ctx)) != 0) {
2618 				goto out;
2619 			}
2620 		}
2621 		/* if no filesec, no attributes */
2622 		if (fsec == NULL) {
2623 			VATTR_RETURN(vap, va_acl, NULL);
2624 			VATTR_RETURN(vap, va_uuuid, kauth_null_guid);
2625 			VATTR_RETURN(vap, va_guuid, kauth_null_guid);
2626 		} else {
2627 			/* looks good, try to return what we were asked for */
2628 			VATTR_RETURN(vap, va_uuuid, fsec->fsec_owner);
2629 			VATTR_RETURN(vap, va_guuid, fsec->fsec_group);
2630 
2631 			/* only return the ACL if we were actually asked for it */
2632 			if (VATTR_IS_ACTIVE(vap, va_acl)) {
2633 				if (fsec->fsec_acl.acl_entrycount == KAUTH_FILESEC_NOACL) {
2634 					VATTR_RETURN(vap, va_acl, NULL);
2635 				} else {
2636 					facl = kauth_acl_alloc(fsec->fsec_acl.acl_entrycount);
2637 					if (facl == NULL) {
2638 						kauth_filesec_free(fsec);
2639 						error = ENOMEM;
2640 						goto out;
2641 					}
2642 					__nochk_bcopy(&fsec->fsec_acl, facl, KAUTH_ACL_COPYSIZE(&fsec->fsec_acl));
2643 					VATTR_RETURN(vap, va_acl, facl);
2644 				}
2645 			}
2646 			kauth_filesec_free(fsec);
2647 		}
2648 	}
2649 	/*
2650 	 * If someone gave us an unsolicited filesec, toss it.  We promise that
2651 	 * we're OK with a filesystem giving us anything back, but our callers
2652 	 * only expect what they asked for.
2653 	 */
2654 	if (VATTR_IS_SUPPORTED(vap, va_acl) && !VATTR_IS_ACTIVE(vap, va_acl)) {
2655 		if (vap->va_acl != NULL) {
2656 			kauth_acl_free(vap->va_acl);
2657 		}
2658 		VATTR_CLEAR_SUPPORTED(vap, va_acl);
2659 	}
2660 
2661 #if 0   /* enable when we have a filesystem only supporting UUIDs */
2662 	/*
2663 	 * Handle the case where we need a UID/GID, but only have extended
2664 	 * security information.
2665 	 */
2666 	if (VATTR_NOT_RETURNED(vap, va_uid) &&
2667 	    VATTR_IS_SUPPORTED(vap, va_uuuid) &&
2668 	    !kauth_guid_equal(&vap->va_uuuid, &kauth_null_guid)) {
2669 		if ((error = kauth_cred_guid2uid(&vap->va_uuuid, &nuid)) == 0) {
2670 			VATTR_RETURN(vap, va_uid, nuid);
2671 		}
2672 	}
2673 	if (VATTR_NOT_RETURNED(vap, va_gid) &&
2674 	    VATTR_IS_SUPPORTED(vap, va_guuid) &&
2675 	    !kauth_guid_equal(&vap->va_guuid, &kauth_null_guid)) {
2676 		if ((error = kauth_cred_guid2gid(&vap->va_guuid, &ngid)) == 0) {
2677 			VATTR_RETURN(vap, va_gid, ngid);
2678 		}
2679 	}
2680 #endif
2681 
2682 	vnode_attr_handle_mnt_ignore_ownership(vap, vp->v_mount, ctx);
2683 
2684 	/*
2685 	 * Synthesise some values that can be reasonably guessed.
2686 	 */
2687 	if (!VATTR_IS_SUPPORTED(vap, va_iosize)) {
2688 		assert(vp->v_mount->mnt_vfsstat.f_iosize <= UINT32_MAX);
2689 		VATTR_RETURN(vap, va_iosize, (uint32_t)vp->v_mount->mnt_vfsstat.f_iosize);
2690 	}
2691 
2692 	if (!VATTR_IS_SUPPORTED(vap, va_flags)) {
2693 		VATTR_RETURN(vap, va_flags, 0);
2694 	}
2695 
2696 	if (!VATTR_IS_SUPPORTED(vap, va_filerev)) {
2697 		VATTR_RETURN(vap, va_filerev, 0);
2698 	}
2699 
2700 	if (!VATTR_IS_SUPPORTED(vap, va_gen)) {
2701 		VATTR_RETURN(vap, va_gen, 0);
2702 	}
2703 
2704 	/*
2705 	 * Default sizes.  Ordering here is important, as later defaults build on earlier ones.
2706 	 */
2707 	if (!VATTR_IS_SUPPORTED(vap, va_data_size)) {
2708 		VATTR_RETURN(vap, va_data_size, 0);
2709 	}
2710 
2711 	/* do we want any of the possibly-computed values? */
2712 	if (VATTR_IS_ACTIVE(vap, va_data_alloc) ||
2713 	    VATTR_IS_ACTIVE(vap, va_total_size) ||
2714 	    VATTR_IS_ACTIVE(vap, va_total_alloc)) {
2715 		/* make sure f_bsize is valid */
2716 		if (vp->v_mount->mnt_vfsstat.f_bsize == 0) {
2717 			if ((error = vfs_update_vfsstat(vp->v_mount, ctx, VFS_KERNEL_EVENT)) != 0) {
2718 				goto out;
2719 			}
2720 		}
2721 
2722 		/* default va_data_alloc from va_data_size */
2723 		if (!VATTR_IS_SUPPORTED(vap, va_data_alloc)) {
2724 			VATTR_RETURN(vap, va_data_alloc, roundup(vap->va_data_size, vp->v_mount->mnt_vfsstat.f_bsize));
2725 		}
2726 
2727 		/* default va_total_size from va_data_size */
2728 		if (!VATTR_IS_SUPPORTED(vap, va_total_size)) {
2729 			VATTR_RETURN(vap, va_total_size, vap->va_data_size);
2730 		}
2731 
2732 		/* default va_total_alloc from va_total_size which is guaranteed at this point */
2733 		if (!VATTR_IS_SUPPORTED(vap, va_total_alloc)) {
2734 			VATTR_RETURN(vap, va_total_alloc, roundup(vap->va_total_size, vp->v_mount->mnt_vfsstat.f_bsize));
2735 		}
2736 	}
2737 
2738 	/*
2739 	 * If we don't have a change time, pull it from the modtime.
2740 	 */
2741 	if (!VATTR_IS_SUPPORTED(vap, va_change_time) && VATTR_IS_SUPPORTED(vap, va_modify_time)) {
2742 		VATTR_RETURN(vap, va_change_time, vap->va_modify_time);
2743 	}
2744 
2745 	/*
2746 	 * This is really only supported for the creation VNOPs, but since the field is there
2747 	 * we should populate it correctly.
2748 	 */
2749 	VATTR_RETURN(vap, va_type, vp->v_type);
2750 
2751 	/*
2752 	 * The fsid can be obtained from the mountpoint directly.
2753 	 */
2754 	if (VATTR_IS_ACTIVE(vap, va_fsid) &&
2755 	    (!VATTR_IS_SUPPORTED(vap, va_fsid) ||
2756 	    vap->va_vaflags & VA_REALFSID || !(vap->va_vaflags & VA_USEFSID))) {
2757 		VATTR_RETURN(vap, va_fsid, vp->v_mount->mnt_vfsstat.f_fsid.val[0]);
2758 	}
2759 
2760 out:
2761 	vap->va_vaflags &= ~VA_USEFSID;
2762 
2763 	return error;
2764 }
2765 
2766 /*
2767  * Choose 32 bit or 64 bit fsid
2768  */
2769 uint64_t
vnode_get_va_fsid(struct vnode_attr * vap)2770 vnode_get_va_fsid(struct vnode_attr *vap)
2771 {
2772 	if (VATTR_IS_SUPPORTED(vap, va_fsid64)) {
2773 		return (uint64_t)vap->va_fsid64.val[0] + ((uint64_t)vap->va_fsid64.val[1] << 32);
2774 	}
2775 	return vap->va_fsid;
2776 }
2777 
2778 /*
2779  * Set the attributes on a vnode in a vnode context.
2780  *
2781  * Parameters:	vp			The vnode whose attributes to set.
2782  *		vap			A pointer to the attributes to set.
2783  *		ctx			The vnode context in which the
2784  *					operation is to be attempted.
2785  *
2786  * Returns:	0			Success
2787  *		!0			errno value
2788  *
2789  * Notes:	The kauth_filesec_t in 'vap', if any, is in host byte order.
2790  *
2791  *		The contents of the data area pointed to by 'vap' may be
2792  *		modified if the vnode is on a filesystem which has been
2793  *		mounted with ingore ownership flags, or by the underlyng
2794  *		VFS itself, or by the fallback code, if the underlying VFS
2795  *		does not support ACL, UUID, or GUUID attributes directly.
2796  *
2797  * XXX:		We should enummerate the possible errno values here, and where
2798  *		in the code they originated.
2799  */
2800 int
vnode_setattr(vnode_t vp,struct vnode_attr * vap,vfs_context_t ctx)2801 vnode_setattr(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)
2802 {
2803 	int     error;
2804 #if CONFIG_FSE
2805 	uint64_t active;
2806 	int     is_perm_change = 0;
2807 	int     is_stat_change = 0;
2808 #endif
2809 
2810 	/*
2811 	 * Reject attempts to set unknown attributes.
2812 	 */
2813 	if (vap->va_active & ~VNODE_ATTR_ALL) {
2814 		return EINVAL;
2815 	}
2816 
2817 	/*
2818 	 * Make sure the filesystem is mounted R/W.
2819 	 * If not, return an error.
2820 	 */
2821 	if (vfs_isrdonly(vp->v_mount)) {
2822 		error = EROFS;
2823 		goto out;
2824 	}
2825 
2826 #if DEVELOPMENT || DEBUG
2827 	/*
2828 	 * XXX VSWAP: Check for entitlements or special flag here
2829 	 * so we can restrict access appropriately.
2830 	 */
2831 #else /* DEVELOPMENT || DEBUG */
2832 
2833 	if (vnode_isswap(vp) && (ctx != vfs_context_kernel())) {
2834 		error = EPERM;
2835 		goto out;
2836 	}
2837 #endif /* DEVELOPMENT || DEBUG */
2838 
2839 #if NAMEDSTREAMS
2840 	/* For streams, va_data_size is the only setable attribute. */
2841 	if ((vp->v_flag & VISNAMEDSTREAM) && (vap->va_active != VNODE_ATTR_va_data_size)) {
2842 		error = EPERM;
2843 		goto out;
2844 	}
2845 #endif
2846 	/* Check for truncation */
2847 	if (VATTR_IS_ACTIVE(vap, va_data_size)) {
2848 		switch (vp->v_type) {
2849 		case VREG:
2850 			/* For regular files it's ok */
2851 			break;
2852 		case VDIR:
2853 			/* Not allowed to truncate directories */
2854 			error = EISDIR;
2855 			goto out;
2856 		default:
2857 			/* For everything else we will clear the bit and let underlying FS decide on the rest */
2858 			VATTR_CLEAR_ACTIVE(vap, va_data_size);
2859 			if (vap->va_active) {
2860 				break;
2861 			}
2862 			/* If it was the only bit set, return success, to handle cases like redirect to /dev/null */
2863 			return 0;
2864 		}
2865 	}
2866 
2867 	/*
2868 	 * If ownership is being ignored on this volume, we silently discard
2869 	 * ownership changes.
2870 	 */
2871 	if (vp->v_mount->mnt_flag & MNT_IGNORE_OWNERSHIP) {
2872 		VATTR_CLEAR_ACTIVE(vap, va_uid);
2873 		VATTR_CLEAR_ACTIVE(vap, va_gid);
2874 	}
2875 
2876 	/*
2877 	 * Make sure that extended security is enabled if we're going to try
2878 	 * to set any.
2879 	 */
2880 	if (!vfs_extendedsecurity(vnode_mount(vp)) &&
2881 	    (VATTR_IS_ACTIVE(vap, va_acl) || VATTR_IS_ACTIVE(vap, va_uuuid) || VATTR_IS_ACTIVE(vap, va_guuid))) {
2882 		KAUTH_DEBUG("SETATTR - returning ENOTSUP to request to set extended security");
2883 		error = ENOTSUP;
2884 		goto out;
2885 	}
2886 
2887 	/* Never allow the setting of any unsupported superuser flags. */
2888 	if (VATTR_IS_ACTIVE(vap, va_flags)) {
2889 		vap->va_flags &= (SF_SUPPORTED | UF_SETTABLE);
2890 	}
2891 
2892 #if CONFIG_FSE
2893 	/*
2894 	 * Remember all of the active attributes that we're
2895 	 * attempting to modify.
2896 	 */
2897 	active = vap->va_active & ~VNODE_ATTR_RDONLY;
2898 #endif
2899 
2900 	error = VNOP_SETATTR(vp, vap, ctx);
2901 
2902 	if ((error == 0) && !VATTR_ALL_SUPPORTED(vap)) {
2903 		error = vnode_setattr_fallback(vp, vap, ctx);
2904 	}
2905 
2906 #if CONFIG_FSE
2907 #define PERMISSION_BITS (VNODE_ATTR_BIT(va_uid) | VNODE_ATTR_BIT(va_uuuid) | \
2908 	                 VNODE_ATTR_BIT(va_gid) | VNODE_ATTR_BIT(va_guuid) | \
2909 	                 VNODE_ATTR_BIT(va_mode) | VNODE_ATTR_BIT(va_acl))
2910 
2911 	/*
2912 	 * Now that we've changed them, decide whether to send an
2913 	 * FSevent.
2914 	 */
2915 	if ((active & PERMISSION_BITS) & vap->va_supported) {
2916 		is_perm_change = 1;
2917 	} else {
2918 		/*
2919 		 * We've already checked the permission bits, and we
2920 		 * also want to filter out access time / backup time
2921 		 * changes.
2922 		 */
2923 		active &= ~(PERMISSION_BITS |
2924 		    VNODE_ATTR_BIT(va_access_time) |
2925 		    VNODE_ATTR_BIT(va_backup_time));
2926 
2927 		/* Anything left to notify about? */
2928 		if (active & vap->va_supported) {
2929 			is_stat_change = 1;
2930 		}
2931 	}
2932 
2933 	if (error == 0) {
2934 		if (is_perm_change) {
2935 			if (need_fsevent(FSE_CHOWN, vp)) {
2936 				add_fsevent(FSE_CHOWN, ctx, FSE_ARG_VNODE, vp, FSE_ARG_DONE);
2937 			}
2938 		} else if (is_stat_change && need_fsevent(FSE_STAT_CHANGED, vp)) {
2939 			add_fsevent(FSE_STAT_CHANGED, ctx, FSE_ARG_VNODE, vp, FSE_ARG_DONE);
2940 		}
2941 	}
2942 #undef PERMISSION_BITS
2943 #endif
2944 
2945 out:
2946 	return error;
2947 }
2948 
2949 /*
2950  * Fallback for setting the attributes on a vnode in a vnode context.  This
2951  * Function will attempt to store ACL, UUID, and GUID information utilizing
2952  * a read/modify/write operation against an EA used as a backing store for
2953  * the object.
2954  *
2955  * Parameters:	vp			The vnode whose attributes to set.
2956  *		vap			A pointer to the attributes to set.
2957  *		ctx			The vnode context in which the
2958  *					operation is to be attempted.
2959  *
2960  * Returns:	0			Success
2961  *		!0			errno value
2962  *
2963  * Notes:	The kauth_filesec_t in 'vap', if any, is in host byte order,
2964  *		as are the fsec and lfsec, if they are used.
2965  *
2966  *		The contents of the data area pointed to by 'vap' may be
2967  *		modified to indicate that the attribute is supported for
2968  *		any given requested attribute.
2969  *
2970  * XXX:		We should enummerate the possible errno values here, and where
2971  *		in the code they originated.
2972  */
2973 int
vnode_setattr_fallback(vnode_t vp,struct vnode_attr * vap,vfs_context_t ctx)2974 vnode_setattr_fallback(vnode_t vp, struct vnode_attr *vap, vfs_context_t ctx)
2975 {
2976 	kauth_filesec_t fsec;
2977 	kauth_acl_t facl;
2978 	struct kauth_filesec lfsec;
2979 	int     error;
2980 
2981 	error = 0;
2982 
2983 	/*
2984 	 * Extended security fallback via extended attributes.
2985 	 *
2986 	 * Note that we do not free the filesec; the caller is expected to
2987 	 * do this.
2988 	 */
2989 	if (VATTR_NOT_RETURNED(vap, va_acl) ||
2990 	    VATTR_NOT_RETURNED(vap, va_uuuid) ||
2991 	    VATTR_NOT_RETURNED(vap, va_guuid)) {
2992 		VFS_DEBUG(ctx, vp, "SETATTR - doing filesec fallback");
2993 
2994 		/*
2995 		 * Fail for file types that we don't permit extended security
2996 		 * to be set on.
2997 		 */
2998 		if (!XATTR_VNODE_SUPPORTED(vp)) {
2999 			VFS_DEBUG(ctx, vp, "SETATTR - Can't write ACL to file type %d", vnode_vtype(vp));
3000 			error = EINVAL;
3001 			goto out;
3002 		}
3003 
3004 		/*
3005 		 * If we don't have all the extended security items, we need
3006 		 * to fetch the existing data to perform a read-modify-write
3007 		 * operation.
3008 		 */
3009 		fsec = NULL;
3010 		if (!VATTR_IS_ACTIVE(vap, va_acl) ||
3011 		    !VATTR_IS_ACTIVE(vap, va_uuuid) ||
3012 		    !VATTR_IS_ACTIVE(vap, va_guuid)) {
3013 			if ((error = vnode_get_filesec(vp, &fsec, ctx)) != 0) {
3014 				KAUTH_DEBUG("SETATTR - ERROR %d fetching filesec for update", error);
3015 				goto out;
3016 			}
3017 		}
3018 		/* if we didn't get a filesec, use our local one */
3019 		if (fsec == NULL) {
3020 			KAUTH_DEBUG("SETATTR - using local filesec for new/full update");
3021 			fsec = &lfsec;
3022 		} else {
3023 			KAUTH_DEBUG("SETATTR - updating existing filesec");
3024 		}
3025 		/* find the ACL */
3026 		facl = &fsec->fsec_acl;
3027 
3028 		/* if we're using the local filesec, we need to initialise it */
3029 		if (fsec == &lfsec) {
3030 			fsec->fsec_magic = KAUTH_FILESEC_MAGIC;
3031 			fsec->fsec_owner = kauth_null_guid;
3032 			fsec->fsec_group = kauth_null_guid;
3033 			facl->acl_entrycount = KAUTH_FILESEC_NOACL;
3034 			facl->acl_flags = 0;
3035 		}
3036 
3037 		/*
3038 		 * Update with the supplied attributes.
3039 		 */
3040 		if (VATTR_IS_ACTIVE(vap, va_uuuid)) {
3041 			KAUTH_DEBUG("SETATTR - updating owner UUID");
3042 			fsec->fsec_owner = vap->va_uuuid;
3043 			VATTR_SET_SUPPORTED(vap, va_uuuid);
3044 		}
3045 		if (VATTR_IS_ACTIVE(vap, va_guuid)) {
3046 			KAUTH_DEBUG("SETATTR - updating group UUID");
3047 			fsec->fsec_group = vap->va_guuid;
3048 			VATTR_SET_SUPPORTED(vap, va_guuid);
3049 		}
3050 		if (VATTR_IS_ACTIVE(vap, va_acl)) {
3051 			if (vap->va_acl == NULL) {
3052 				KAUTH_DEBUG("SETATTR - removing ACL");
3053 				facl->acl_entrycount = KAUTH_FILESEC_NOACL;
3054 			} else {
3055 				KAUTH_DEBUG("SETATTR - setting ACL with %d entries", vap->va_acl->acl_entrycount);
3056 				facl = vap->va_acl;
3057 			}
3058 			VATTR_SET_SUPPORTED(vap, va_acl);
3059 		}
3060 
3061 		/*
3062 		 * If the filesec data is all invalid, we can just remove
3063 		 * the EA completely.
3064 		 */
3065 		if ((facl->acl_entrycount == KAUTH_FILESEC_NOACL) &&
3066 		    kauth_guid_equal(&fsec->fsec_owner, &kauth_null_guid) &&
3067 		    kauth_guid_equal(&fsec->fsec_group, &kauth_null_guid)) {
3068 			error = vn_removexattr(vp, KAUTH_FILESEC_XATTR, XATTR_NOSECURITY, ctx);
3069 			/* no attribute is ok, nothing to delete */
3070 			if (error == ENOATTR) {
3071 				error = 0;
3072 			}
3073 			VFS_DEBUG(ctx, vp, "SETATTR - remove filesec returning %d", error);
3074 		} else {
3075 			/* write the EA */
3076 			error = vnode_set_filesec(vp, fsec, facl, ctx);
3077 			VFS_DEBUG(ctx, vp, "SETATTR - update filesec returning %d", error);
3078 		}
3079 
3080 		/* if we fetched a filesec, dispose of the buffer */
3081 		if (fsec != &lfsec) {
3082 			kauth_filesec_free(fsec);
3083 		}
3084 	}
3085 out:
3086 
3087 	return error;
3088 }
3089 
3090 /*
3091  * Upcall for a filesystem to tell VFS about an EVFILT_VNODE-type
3092  * event on a vnode.
3093  */
3094 int
vnode_notify(vnode_t vp,uint32_t events,struct vnode_attr * vap)3095 vnode_notify(vnode_t vp, uint32_t events, struct vnode_attr *vap)
3096 {
3097 	/* These are the same as the corresponding knotes, at least for now.  Cheating a little. */
3098 	uint32_t knote_mask = (VNODE_EVENT_WRITE | VNODE_EVENT_DELETE | VNODE_EVENT_RENAME
3099 	    | VNODE_EVENT_LINK | VNODE_EVENT_EXTEND | VNODE_EVENT_ATTRIB);
3100 	uint32_t dir_contents_mask = (VNODE_EVENT_DIR_CREATED | VNODE_EVENT_FILE_CREATED
3101 	    | VNODE_EVENT_DIR_REMOVED | VNODE_EVENT_FILE_REMOVED);
3102 	uint32_t knote_events = (events & knote_mask);
3103 
3104 	/* Permissions are not explicitly part of the kqueue model */
3105 	if (events & VNODE_EVENT_PERMS) {
3106 		knote_events |= NOTE_ATTRIB;
3107 	}
3108 
3109 	/* Directory contents information just becomes NOTE_WRITE */
3110 	if ((vnode_isdir(vp)) && (events & dir_contents_mask)) {
3111 		knote_events |= NOTE_WRITE;
3112 	}
3113 
3114 	if (knote_events) {
3115 		lock_vnode_and_post(vp, knote_events);
3116 #if CONFIG_FSE
3117 		if (vap != NULL) {
3118 			create_fsevent_from_kevent(vp, events, vap);
3119 		}
3120 #else
3121 		(void)vap;
3122 #endif
3123 	}
3124 
3125 	return 0;
3126 }
3127 
3128 
3129 
3130 int
vnode_isdyldsharedcache(vnode_t vp)3131 vnode_isdyldsharedcache(vnode_t vp)
3132 {
3133 	return (vp->v_flag & VSHARED_DYLD) ? 1 : 0;
3134 }
3135 
3136 
3137 /*
3138  * For a filesystem that isn't tracking its own vnode watchers:
3139  * check whether a vnode is being monitored.
3140  */
3141 int
vnode_ismonitored(vnode_t vp)3142 vnode_ismonitored(vnode_t vp)
3143 {
3144 	return vp->v_knotes.slh_first != NULL;
3145 }
3146 
3147 int
vnode_getbackingvnode(vnode_t in_vp,vnode_t * out_vpp)3148 vnode_getbackingvnode(vnode_t in_vp, vnode_t* out_vpp)
3149 {
3150 	if (out_vpp) {
3151 		*out_vpp = NULLVP;
3152 	}
3153 #if NULLFS
3154 	return nullfs_getbackingvnode(in_vp, out_vpp);
3155 #else
3156 #pragma unused(in_vp)
3157 	return ENOENT;
3158 #endif
3159 }
3160 
3161 /*
3162  * Initialize a struct vnode_attr and activate the attributes required
3163  * by the vnode_notify() call.
3164  */
3165 int
vfs_get_notify_attributes(struct vnode_attr * vap)3166 vfs_get_notify_attributes(struct vnode_attr *vap)
3167 {
3168 	VATTR_INIT(vap);
3169 	vap->va_active = VNODE_NOTIFY_ATTRS;
3170 	return 0;
3171 }
3172 
3173 #if CONFIG_TRIGGERS
3174 int
vfs_settriggercallback(fsid_t * fsid,vfs_trigger_callback_t vtc,void * data,uint32_t flags __unused,vfs_context_t ctx)3175 vfs_settriggercallback(fsid_t *fsid, vfs_trigger_callback_t vtc, void *data, uint32_t flags __unused, vfs_context_t ctx)
3176 {
3177 	int error;
3178 	mount_t mp;
3179 
3180 	mp = mount_list_lookupby_fsid(fsid, 0 /* locked */, 1 /* withref */);
3181 	if (mp == NULL) {
3182 		return ENOENT;
3183 	}
3184 
3185 	error = vfs_busy(mp, LK_NOWAIT);
3186 	mount_iterdrop(mp);
3187 
3188 	if (error != 0) {
3189 		return ENOENT;
3190 	}
3191 
3192 	mount_lock(mp);
3193 	if (mp->mnt_triggercallback != NULL) {
3194 		error = EBUSY;
3195 		mount_unlock(mp);
3196 		goto out;
3197 	}
3198 
3199 	mp->mnt_triggercallback = vtc;
3200 	mp->mnt_triggerdata = data;
3201 	mount_unlock(mp);
3202 
3203 	mp->mnt_triggercallback(mp, VTC_REPLACE, data, ctx);
3204 
3205 out:
3206 	vfs_unbusy(mp);
3207 	return 0;
3208 }
3209 #endif /* CONFIG_TRIGGERS */
3210 
3211 /*
3212  *  Definition of vnode operations.
3213  */
3214 
3215 #if 0
3216 /*
3217 *#
3218 *#% lookup       dvp     L ? ?
3219 *#% lookup       vpp     - L -
3220 */
3221 struct vnop_lookup_args {
3222 	struct vnodeop_desc *a_desc;
3223 	vnode_t a_dvp;
3224 	vnode_t *a_vpp;
3225 	struct componentname *a_cnp;
3226 	vfs_context_t a_context;
3227 };
3228 #endif /* 0*/
3229 
3230 /*
3231  * Returns:	0			Success
3232  *	lock_fsnode:ENOENT		No such file or directory [only for VFS
3233  *					 that is not thread safe & vnode is
3234  *					 currently being/has been terminated]
3235  *	<vfs_lookup>:ENAMETOOLONG
3236  *	<vfs_lookup>:ENOENT
3237  *	<vfs_lookup>:EJUSTRETURN
3238  *	<vfs_lookup>:EPERM
3239  *	<vfs_lookup>:EISDIR
3240  *	<vfs_lookup>:ENOTDIR
3241  *	<vfs_lookup>:???
3242  *
3243  * Note:	The return codes from the underlying VFS's lookup routine can't
3244  *		be fully enumerated here, since third party VFS authors may not
3245  *		limit their error returns to the ones documented here, even
3246  *		though this may result in some programs functioning incorrectly.
3247  *
3248  *		The return codes documented above are those which may currently
3249  *		be returned by HFS from hfs_lookup, not including additional
3250  *		error code which may be propagated from underlying routines.
3251  */
3252 errno_t
VNOP_LOOKUP(vnode_t dvp,vnode_t * vpp,struct componentname * cnp,vfs_context_t ctx)3253 VNOP_LOOKUP(vnode_t dvp, vnode_t *vpp, struct componentname *cnp, vfs_context_t ctx)
3254 {
3255 	int _err;
3256 	struct vnop_lookup_args a;
3257 
3258 	a.a_desc = &vnop_lookup_desc;
3259 	a.a_dvp = dvp;
3260 	a.a_vpp = vpp;
3261 	a.a_cnp = cnp;
3262 	a.a_context = ctx;
3263 
3264 	_err = (*dvp->v_op[vnop_lookup_desc.vdesc_offset])(&a);
3265 	if (_err == 0 && *vpp) {
3266 		DTRACE_FSINFO(lookup, vnode_t, *vpp);
3267 	}
3268 
3269 	return _err;
3270 }
3271 
3272 #if 0
3273 struct vnop_compound_open_args {
3274 	struct vnodeop_desc *a_desc;
3275 	vnode_t a_dvp;
3276 	vnode_t *a_vpp;
3277 	struct componentname *a_cnp;
3278 	int32_t a_flags;
3279 	int32_t a_fmode;
3280 	struct vnode_attr *a_vap;
3281 	vfs_context_t a_context;
3282 	void *a_reserved;
3283 };
3284 #endif /* 0 */
3285 
3286 int
VNOP_COMPOUND_OPEN(vnode_t dvp,vnode_t * vpp,struct nameidata * ndp,int32_t flags,int32_t fmode,uint32_t * statusp,struct vnode_attr * vap,vfs_context_t ctx)3287 VNOP_COMPOUND_OPEN(vnode_t dvp, vnode_t *vpp, struct nameidata *ndp, int32_t flags, int32_t fmode, uint32_t *statusp, struct vnode_attr *vap, vfs_context_t ctx)
3288 {
3289 	int _err;
3290 	struct vnop_compound_open_args a;
3291 	int did_create = 0;
3292 	int want_create;
3293 	uint32_t tmp_status = 0;
3294 	struct componentname *cnp = &ndp->ni_cnd;
3295 
3296 	want_create = (flags & O_CREAT);
3297 
3298 	a.a_desc = &vnop_compound_open_desc;
3299 	a.a_dvp = dvp;
3300 	a.a_vpp = vpp; /* Could be NULL */
3301 	a.a_cnp = cnp;
3302 	a.a_flags = flags;
3303 	a.a_fmode = fmode;
3304 	a.a_status = (statusp != NULL) ? statusp : &tmp_status;
3305 	a.a_vap = vap;
3306 	a.a_context = ctx;
3307 	a.a_open_create_authorizer = vn_authorize_create;
3308 	a.a_open_existing_authorizer = vn_authorize_open_existing;
3309 	a.a_reserved = NULL;
3310 
3311 	if (dvp == NULLVP) {
3312 		panic("No dvp?");
3313 	}
3314 	if (want_create && !vap) {
3315 		panic("Want create, but no vap?");
3316 	}
3317 	if (!want_create && vap) {
3318 		panic("Don't want create, but have a vap?");
3319 	}
3320 
3321 	_err = (*dvp->v_op[vnop_compound_open_desc.vdesc_offset])(&a);
3322 	if (want_create) {
3323 		if (_err == 0 && *vpp) {
3324 			DTRACE_FSINFO(compound_open, vnode_t, *vpp);
3325 		} else {
3326 			DTRACE_FSINFO(compound_open, vnode_t, dvp);
3327 		}
3328 	} else {
3329 		DTRACE_FSINFO(compound_open, vnode_t, *vpp);
3330 	}
3331 
3332 	did_create = (*a.a_status & COMPOUND_OPEN_STATUS_DID_CREATE);
3333 
3334 	if (did_create && !want_create) {
3335 		panic("Filesystem did a create, even though none was requested?");
3336 	}
3337 
3338 	if (did_create) {
3339 #if CONFIG_APPLEDOUBLE
3340 		if (!NATIVE_XATTR(dvp)) {
3341 			/*
3342 			 * Remove stale Apple Double file (if any).
3343 			 */
3344 			xattrfile_remove(dvp, cnp->cn_nameptr, ctx, 0);
3345 		}
3346 #endif /* CONFIG_APPLEDOUBLE */
3347 		/* On create, provide kqueue notification */
3348 		post_event_if_success(dvp, _err, NOTE_WRITE);
3349 	}
3350 
3351 	lookup_compound_vnop_post_hook(_err, dvp, *vpp, ndp, did_create);
3352 #if 0 /* FSEvents... */
3353 	if (*vpp && _err && _err != EKEEPLOOKING) {
3354 		vnode_put(*vpp);
3355 		*vpp = NULLVP;
3356 	}
3357 #endif /* 0 */
3358 
3359 	return _err;
3360 }
3361 
3362 #if 0
3363 struct vnop_create_args {
3364 	struct vnodeop_desc *a_desc;
3365 	vnode_t a_dvp;
3366 	vnode_t *a_vpp;
3367 	struct componentname *a_cnp;
3368 	struct vnode_attr *a_vap;
3369 	vfs_context_t a_context;
3370 };
3371 #endif /* 0*/
3372 errno_t
VNOP_CREATE(vnode_t dvp,vnode_t * vpp,struct componentname * cnp,struct vnode_attr * vap,vfs_context_t ctx)3373 VNOP_CREATE(vnode_t dvp, vnode_t * vpp, struct componentname * cnp, struct vnode_attr * vap, vfs_context_t ctx)
3374 {
3375 	int _err;
3376 	struct vnop_create_args a;
3377 
3378 	a.a_desc = &vnop_create_desc;
3379 	a.a_dvp = dvp;
3380 	a.a_vpp = vpp;
3381 	a.a_cnp = cnp;
3382 	a.a_vap = vap;
3383 	a.a_context = ctx;
3384 
3385 	_err = (*dvp->v_op[vnop_create_desc.vdesc_offset])(&a);
3386 	if (_err == 0 && *vpp) {
3387 		DTRACE_FSINFO(create, vnode_t, *vpp);
3388 	}
3389 
3390 #if CONFIG_APPLEDOUBLE
3391 	if (_err == 0 && !NATIVE_XATTR(dvp)) {
3392 		/*
3393 		 * Remove stale Apple Double file (if any).
3394 		 */
3395 		xattrfile_remove(dvp, cnp->cn_nameptr, ctx, 0);
3396 	}
3397 #endif /* CONFIG_APPLEDOUBLE */
3398 
3399 	post_event_if_success(dvp, _err, NOTE_WRITE);
3400 
3401 	return _err;
3402 }
3403 
3404 #if 0
3405 /*
3406 *#
3407 *#% whiteout     dvp     L L L
3408 *#% whiteout     cnp     - - -
3409 *#% whiteout     flag    - - -
3410 *#
3411 */
3412 struct vnop_whiteout_args {
3413 	struct vnodeop_desc *a_desc;
3414 	vnode_t a_dvp;
3415 	struct componentname *a_cnp;
3416 	int a_flags;
3417 	vfs_context_t a_context;
3418 };
3419 #endif /* 0*/
3420 errno_t
VNOP_WHITEOUT(__unused vnode_t dvp,__unused struct componentname * cnp,__unused int flags,__unused vfs_context_t ctx)3421 VNOP_WHITEOUT(__unused vnode_t dvp, __unused struct componentname *cnp,
3422     __unused int flags, __unused vfs_context_t ctx)
3423 {
3424 	return ENOTSUP;       // XXX OBSOLETE
3425 }
3426 
3427 #if 0
3428 /*
3429 *#
3430 *#% mknod        dvp     L U U
3431 *#% mknod        vpp     - X -
3432 *#
3433 */
3434 struct vnop_mknod_args {
3435 	struct vnodeop_desc *a_desc;
3436 	vnode_t a_dvp;
3437 	vnode_t *a_vpp;
3438 	struct componentname *a_cnp;
3439 	struct vnode_attr *a_vap;
3440 	vfs_context_t a_context;
3441 };
3442 #endif /* 0*/
3443 errno_t
VNOP_MKNOD(vnode_t dvp,vnode_t * vpp,struct componentname * cnp,struct vnode_attr * vap,vfs_context_t ctx)3444 VNOP_MKNOD(vnode_t dvp, vnode_t * vpp, struct componentname * cnp, struct vnode_attr * vap, vfs_context_t ctx)
3445 {
3446 	int _err;
3447 	struct vnop_mknod_args a;
3448 
3449 	a.a_desc = &vnop_mknod_desc;
3450 	a.a_dvp = dvp;
3451 	a.a_vpp = vpp;
3452 	a.a_cnp = cnp;
3453 	a.a_vap = vap;
3454 	a.a_context = ctx;
3455 
3456 	_err = (*dvp->v_op[vnop_mknod_desc.vdesc_offset])(&a);
3457 	if (_err == 0 && *vpp) {
3458 		DTRACE_FSINFO(mknod, vnode_t, *vpp);
3459 	}
3460 
3461 	post_event_if_success(dvp, _err, NOTE_WRITE);
3462 
3463 	return _err;
3464 }
3465 
3466 #if 0
3467 /*
3468 *#
3469 *#% open         vp      L L L
3470 *#
3471 */
3472 struct vnop_open_args {
3473 	struct vnodeop_desc *a_desc;
3474 	vnode_t a_vp;
3475 	int a_mode;
3476 	vfs_context_t a_context;
3477 };
3478 #endif /* 0*/
3479 errno_t
VNOP_OPEN(vnode_t vp,int mode,vfs_context_t ctx)3480 VNOP_OPEN(vnode_t vp, int mode, vfs_context_t ctx)
3481 {
3482 	int _err;
3483 	struct vnop_open_args a;
3484 
3485 	if (ctx == NULL) {
3486 		ctx = vfs_context_current();
3487 	}
3488 	a.a_desc = &vnop_open_desc;
3489 	a.a_vp = vp;
3490 	a.a_mode = mode;
3491 	a.a_context = ctx;
3492 
3493 	_err = (*vp->v_op[vnop_open_desc.vdesc_offset])(&a);
3494 	DTRACE_FSINFO(open, vnode_t, vp);
3495 
3496 	return _err;
3497 }
3498 
3499 #if 0
3500 /*
3501 *#
3502 *#% close        vp      U U U
3503 *#
3504 */
3505 struct vnop_close_args {
3506 	struct vnodeop_desc *a_desc;
3507 	vnode_t a_vp;
3508 	int a_fflag;
3509 	vfs_context_t a_context;
3510 };
3511 #endif /* 0*/
3512 errno_t
VNOP_CLOSE(vnode_t vp,int fflag,vfs_context_t ctx)3513 VNOP_CLOSE(vnode_t vp, int fflag, vfs_context_t ctx)
3514 {
3515 	int _err;
3516 	struct vnop_close_args a;
3517 
3518 	if (ctx == NULL) {
3519 		ctx = vfs_context_current();
3520 	}
3521 	a.a_desc = &vnop_close_desc;
3522 	a.a_vp = vp;
3523 	a.a_fflag = fflag;
3524 	a.a_context = ctx;
3525 
3526 	_err = (*vp->v_op[vnop_close_desc.vdesc_offset])(&a);
3527 	DTRACE_FSINFO(close, vnode_t, vp);
3528 
3529 	return _err;
3530 }
3531 
3532 #if 0
3533 /*
3534 *#
3535 *#% access       vp      L L L
3536 *#
3537 */
3538 struct vnop_access_args {
3539 	struct vnodeop_desc *a_desc;
3540 	vnode_t a_vp;
3541 	int a_action;
3542 	vfs_context_t a_context;
3543 };
3544 #endif /* 0*/
3545 errno_t
VNOP_ACCESS(vnode_t vp,int action,vfs_context_t ctx)3546 VNOP_ACCESS(vnode_t vp, int action, vfs_context_t ctx)
3547 {
3548 	int _err;
3549 	struct vnop_access_args a;
3550 
3551 	if (ctx == NULL) {
3552 		ctx = vfs_context_current();
3553 	}
3554 	a.a_desc = &vnop_access_desc;
3555 	a.a_vp = vp;
3556 	a.a_action = action;
3557 	a.a_context = ctx;
3558 
3559 	_err = (*vp->v_op[vnop_access_desc.vdesc_offset])(&a);
3560 	DTRACE_FSINFO(access, vnode_t, vp);
3561 
3562 	return _err;
3563 }
3564 
3565 #if 0
3566 /*
3567 *#
3568 *#% getattr      vp      = = =
3569 *#
3570 */
3571 struct vnop_getattr_args {
3572 	struct vnodeop_desc *a_desc;
3573 	vnode_t a_vp;
3574 	struct vnode_attr *a_vap;
3575 	vfs_context_t a_context;
3576 };
3577 #endif /* 0*/
3578 errno_t
VNOP_GETATTR(vnode_t vp,struct vnode_attr * vap,vfs_context_t ctx)3579 VNOP_GETATTR(vnode_t vp, struct vnode_attr * vap, vfs_context_t ctx)
3580 {
3581 	int _err;
3582 	struct vnop_getattr_args a;
3583 
3584 	a.a_desc = &vnop_getattr_desc;
3585 	a.a_vp = vp;
3586 	a.a_vap = vap;
3587 	a.a_context = ctx;
3588 
3589 	_err = (*vp->v_op[vnop_getattr_desc.vdesc_offset])(&a);
3590 	DTRACE_FSINFO(getattr, vnode_t, vp);
3591 
3592 	return _err;
3593 }
3594 
3595 #if 0
3596 /*
3597 *#
3598 *#% setattr      vp      L L L
3599 *#
3600 */
3601 struct vnop_setattr_args {
3602 	struct vnodeop_desc *a_desc;
3603 	vnode_t a_vp;
3604 	struct vnode_attr *a_vap;
3605 	vfs_context_t a_context;
3606 };
3607 #endif /* 0*/
3608 errno_t
VNOP_SETATTR(vnode_t vp,struct vnode_attr * vap,vfs_context_t ctx)3609 VNOP_SETATTR(vnode_t vp, struct vnode_attr * vap, vfs_context_t ctx)
3610 {
3611 	int _err;
3612 	struct vnop_setattr_args a;
3613 
3614 	a.a_desc = &vnop_setattr_desc;
3615 	a.a_vp = vp;
3616 	a.a_vap = vap;
3617 	a.a_context = ctx;
3618 
3619 	_err = (*vp->v_op[vnop_setattr_desc.vdesc_offset])(&a);
3620 	DTRACE_FSINFO(setattr, vnode_t, vp);
3621 
3622 #if CONFIG_APPLEDOUBLE
3623 	/*
3624 	 * Shadow uid/gid/mod change to extended attribute file.
3625 	 */
3626 	if (_err == 0 && !NATIVE_XATTR(vp)) {
3627 		struct vnode_attr va;
3628 		int change = 0;
3629 
3630 		VATTR_INIT(&va);
3631 		if (VATTR_IS_ACTIVE(vap, va_uid)) {
3632 			VATTR_SET(&va, va_uid, vap->va_uid);
3633 			change = 1;
3634 		}
3635 		if (VATTR_IS_ACTIVE(vap, va_gid)) {
3636 			VATTR_SET(&va, va_gid, vap->va_gid);
3637 			change = 1;
3638 		}
3639 		if (VATTR_IS_ACTIVE(vap, va_mode)) {
3640 			VATTR_SET(&va, va_mode, vap->va_mode);
3641 			change = 1;
3642 		}
3643 		if (change) {
3644 			vnode_t dvp;
3645 			const char   *vname;
3646 
3647 			dvp = vnode_getparent(vp);
3648 			vname = vnode_getname(vp);
3649 
3650 			xattrfile_setattr(dvp, vname, &va, ctx);
3651 			if (dvp != NULLVP) {
3652 				vnode_put(dvp);
3653 			}
3654 			if (vname != NULL) {
3655 				vnode_putname(vname);
3656 			}
3657 		}
3658 	}
3659 #endif /* CONFIG_APPLEDOUBLE */
3660 
3661 	/*
3662 	 * If we have changed any of the things about the file that are likely
3663 	 * to result in changes to authorization results, blow the vnode auth
3664 	 * cache
3665 	 */
3666 	if (_err == 0 && (
3667 		    VATTR_IS_SUPPORTED(vap, va_mode) ||
3668 		    VATTR_IS_SUPPORTED(vap, va_uid) ||
3669 		    VATTR_IS_SUPPORTED(vap, va_gid) ||
3670 		    VATTR_IS_SUPPORTED(vap, va_flags) ||
3671 		    VATTR_IS_SUPPORTED(vap, va_acl) ||
3672 		    VATTR_IS_SUPPORTED(vap, va_uuuid) ||
3673 		    VATTR_IS_SUPPORTED(vap, va_guuid))) {
3674 		vnode_uncache_authorized_action(vp, KAUTH_INVALIDATE_CACHED_RIGHTS);
3675 
3676 #if NAMEDSTREAMS
3677 		if (vfs_authopaque(vp->v_mount) && vnode_hasnamedstreams(vp)) {
3678 			vnode_t svp;
3679 			if (vnode_getnamedstream(vp, &svp, XATTR_RESOURCEFORK_NAME, NS_OPEN, 0, ctx) == 0) {
3680 				vnode_uncache_authorized_action(svp, KAUTH_INVALIDATE_CACHED_RIGHTS);
3681 				vnode_put(svp);
3682 			}
3683 		}
3684 #endif /* NAMEDSTREAMS */
3685 	}
3686 
3687 
3688 	post_event_if_success(vp, _err, NOTE_ATTRIB);
3689 
3690 	return _err;
3691 }
3692 
3693 
3694 #if 0
3695 /*
3696 *#
3697 *#% read         vp      L L L
3698 *#
3699 */
3700 struct vnop_read_args {
3701 	struct vnodeop_desc *a_desc;
3702 	vnode_t a_vp;
3703 	struct uio *a_uio;
3704 	int a_ioflag;
3705 	vfs_context_t a_context;
3706 };
3707 #endif /* 0*/
3708 errno_t
VNOP_READ(vnode_t vp,struct uio * uio,int ioflag,vfs_context_t ctx)3709 VNOP_READ(vnode_t vp, struct uio * uio, int ioflag, vfs_context_t ctx)
3710 {
3711 	int _err;
3712 	struct vnop_read_args a;
3713 #if CONFIG_DTRACE
3714 	user_ssize_t resid = uio_resid(uio);
3715 #endif
3716 
3717 	if (ctx == NULL) {
3718 		return EINVAL;
3719 	}
3720 
3721 	a.a_desc = &vnop_read_desc;
3722 	a.a_vp = vp;
3723 	a.a_uio = uio;
3724 	a.a_ioflag = ioflag;
3725 	a.a_context = ctx;
3726 
3727 	_err = (*vp->v_op[vnop_read_desc.vdesc_offset])(&a);
3728 	DTRACE_FSINFO_IO(read,
3729 	    vnode_t, vp, user_ssize_t, (resid - uio_resid(uio)));
3730 
3731 	return _err;
3732 }
3733 
3734 
3735 #if 0
3736 /*
3737 *#
3738 *#% write        vp      L L L
3739 *#
3740 */
3741 struct vnop_write_args {
3742 	struct vnodeop_desc *a_desc;
3743 	vnode_t a_vp;
3744 	struct uio *a_uio;
3745 	int a_ioflag;
3746 	vfs_context_t a_context;
3747 };
3748 #endif /* 0*/
3749 errno_t
VNOP_WRITE(vnode_t vp,struct uio * uio,int ioflag,vfs_context_t ctx)3750 VNOP_WRITE(vnode_t vp, struct uio * uio, int ioflag, vfs_context_t ctx)
3751 {
3752 	struct vnop_write_args a;
3753 	int _err;
3754 #if CONFIG_DTRACE
3755 	user_ssize_t resid = uio_resid(uio);
3756 #endif
3757 
3758 	if (ctx == NULL) {
3759 		return EINVAL;
3760 	}
3761 
3762 	a.a_desc = &vnop_write_desc;
3763 	a.a_vp = vp;
3764 	a.a_uio = uio;
3765 	a.a_ioflag = ioflag;
3766 	a.a_context = ctx;
3767 
3768 	_err = (*vp->v_op[vnop_write_desc.vdesc_offset])(&a);
3769 	DTRACE_FSINFO_IO(write,
3770 	    vnode_t, vp, user_ssize_t, (resid - uio_resid(uio)));
3771 
3772 	post_event_if_success(vp, _err, NOTE_WRITE);
3773 
3774 	return _err;
3775 }
3776 
3777 
3778 #if 0
3779 /*
3780 *#
3781 *#% ioctl        vp      U U U
3782 *#
3783 */
3784 struct vnop_ioctl_args {
3785 	struct vnodeop_desc *a_desc;
3786 	vnode_t a_vp;
3787 	u_long a_command;
3788 	caddr_t a_data;
3789 	int a_fflag;
3790 	vfs_context_t a_context;
3791 };
3792 #endif /* 0*/
3793 errno_t
VNOP_IOCTL(vnode_t vp,u_long command,caddr_t data,int fflag,vfs_context_t ctx)3794 VNOP_IOCTL(vnode_t vp, u_long command, caddr_t data, int fflag, vfs_context_t ctx)
3795 {
3796 	int _err;
3797 	struct vnop_ioctl_args a;
3798 
3799 	if (ctx == NULL) {
3800 		ctx = vfs_context_current();
3801 	}
3802 
3803 	/*
3804 	 * This check should probably have been put in the TTY code instead...
3805 	 *
3806 	 * We have to be careful about what we assume during startup and shutdown.
3807 	 * We have to be able to use the root filesystem's device vnode even when
3808 	 * devfs isn't mounted (yet/anymore), so we can't go looking at its mount
3809 	 * structure.  If there is no data pointer, it doesn't matter whether
3810 	 * the device is 64-bit ready.  Any command (like DKIOCSYNCHRONIZE)
3811 	 * which passes NULL for its data pointer can therefore be used during
3812 	 * mount or unmount of the root filesystem.
3813 	 *
3814 	 * Depending on what root filesystems need to do during mount/unmount, we
3815 	 * may need to loosen this check again in the future.
3816 	 */
3817 	if (vfs_context_is64bit(ctx) && !(vnode_ischr(vp) || vnode_isblk(vp))) {
3818 		if (data != NULL && !vnode_vfs64bitready(vp)) {
3819 			return ENOTTY;
3820 		}
3821 	}
3822 
3823 	if ((command == DKIOCISSOLIDSTATE) && (vp == rootvp) && rootvp_is_ssd && data) {
3824 		*data = 1;
3825 		return 0;
3826 	}
3827 
3828 	a.a_desc = &vnop_ioctl_desc;
3829 	a.a_vp = vp;
3830 	a.a_command = command;
3831 	a.a_data = data;
3832 	a.a_fflag = fflag;
3833 	a.a_context = ctx;
3834 
3835 	_err = (*vp->v_op[vnop_ioctl_desc.vdesc_offset])(&a);
3836 	DTRACE_FSINFO(ioctl, vnode_t, vp);
3837 
3838 	return _err;
3839 }
3840 
3841 
3842 #if 0
3843 /*
3844 *#
3845 *#% select       vp      U U U
3846 *#
3847 */
3848 struct vnop_select_args {
3849 	struct vnodeop_desc *a_desc;
3850 	vnode_t a_vp;
3851 	int a_which;
3852 	int a_fflags;
3853 	void *a_wql;
3854 	vfs_context_t a_context;
3855 };
3856 #endif /* 0*/
3857 errno_t
VNOP_SELECT(vnode_t vp,int which,int fflags,void * wql,vfs_context_t ctx)3858 VNOP_SELECT(vnode_t vp, int which, int fflags, void * wql, vfs_context_t ctx)
3859 {
3860 	int _err;
3861 	struct vnop_select_args a;
3862 
3863 	if (ctx == NULL) {
3864 		ctx = vfs_context_current();
3865 	}
3866 	a.a_desc = &vnop_select_desc;
3867 	a.a_vp = vp;
3868 	a.a_which = which;
3869 	a.a_fflags = fflags;
3870 	a.a_context = ctx;
3871 	a.a_wql = wql;
3872 
3873 	_err = (*vp->v_op[vnop_select_desc.vdesc_offset])(&a);
3874 	DTRACE_FSINFO(select, vnode_t, vp);
3875 
3876 	return _err;
3877 }
3878 
3879 
3880 #if 0
3881 /*
3882 *#
3883 *#% exchange fvp         L L L
3884 *#% exchange tvp         L L L
3885 *#
3886 */
3887 struct vnop_exchange_args {
3888 	struct vnodeop_desc *a_desc;
3889 	vnode_t a_fvp;
3890 	vnode_t a_tvp;
3891 	int a_options;
3892 	vfs_context_t a_context;
3893 };
3894 #endif /* 0*/
3895 errno_t
VNOP_EXCHANGE(vnode_t fvp,vnode_t tvp,int options,vfs_context_t ctx)3896 VNOP_EXCHANGE(vnode_t fvp, vnode_t tvp, int options, vfs_context_t ctx)
3897 {
3898 	int _err;
3899 	struct vnop_exchange_args a;
3900 
3901 	a.a_desc = &vnop_exchange_desc;
3902 	a.a_fvp = fvp;
3903 	a.a_tvp = tvp;
3904 	a.a_options = options;
3905 	a.a_context = ctx;
3906 
3907 	_err = (*fvp->v_op[vnop_exchange_desc.vdesc_offset])(&a);
3908 	DTRACE_FSINFO(exchange, vnode_t, fvp);
3909 
3910 	/* Don't post NOTE_WRITE because file descriptors follow the data ... */
3911 	post_event_if_success(fvp, _err, NOTE_ATTRIB);
3912 	post_event_if_success(tvp, _err, NOTE_ATTRIB);
3913 
3914 	return _err;
3915 }
3916 
3917 
3918 #if 0
3919 /*
3920 *#
3921 *#% revoke       vp      U U U
3922 *#
3923 */
3924 struct vnop_revoke_args {
3925 	struct vnodeop_desc *a_desc;
3926 	vnode_t a_vp;
3927 	int a_flags;
3928 	vfs_context_t a_context;
3929 };
3930 #endif /* 0*/
3931 errno_t
VNOP_REVOKE(vnode_t vp,int flags,vfs_context_t ctx)3932 VNOP_REVOKE(vnode_t vp, int flags, vfs_context_t ctx)
3933 {
3934 	struct vnop_revoke_args a;
3935 	int _err;
3936 
3937 	a.a_desc = &vnop_revoke_desc;
3938 	a.a_vp = vp;
3939 	a.a_flags = flags;
3940 	a.a_context = ctx;
3941 
3942 	_err = (*vp->v_op[vnop_revoke_desc.vdesc_offset])(&a);
3943 	DTRACE_FSINFO(revoke, vnode_t, vp);
3944 
3945 	return _err;
3946 }
3947 
3948 
3949 #if 0
3950 /*
3951 *#
3952 *# mmap_check - vp U U U
3953 *#
3954 */
3955 struct vnop_mmap_check_args {
3956 	struct vnodeop_desc *a_desc;
3957 	vnode_t a_vp;
3958 	int a_flags;
3959 	vfs_context_t a_context;
3960 };
3961 #endif /* 0 */
3962 errno_t
VNOP_MMAP_CHECK(vnode_t vp,int flags,vfs_context_t ctx)3963 VNOP_MMAP_CHECK(vnode_t vp, int flags, vfs_context_t ctx)
3964 {
3965 	int _err;
3966 	struct vnop_mmap_check_args a;
3967 
3968 	a.a_desc = &vnop_mmap_check_desc;
3969 	a.a_vp = vp;
3970 	a.a_flags = flags;
3971 	a.a_context = ctx;
3972 
3973 	_err = (*vp->v_op[vnop_mmap_check_desc.vdesc_offset])(&a);
3974 	if (_err == ENOTSUP) {
3975 		_err = 0;
3976 	}
3977 	DTRACE_FSINFO(mmap_check, vnode_t, vp);
3978 
3979 	return _err;
3980 }
3981 
3982 #if 0
3983 /*
3984 *#
3985 *# mmap - vp U U U
3986 *#
3987 */
3988 struct vnop_mmap_args {
3989 	struct vnodeop_desc *a_desc;
3990 	vnode_t a_vp;
3991 	int a_fflags;
3992 	vfs_context_t a_context;
3993 };
3994 #endif /* 0*/
3995 errno_t
VNOP_MMAP(vnode_t vp,int fflags,vfs_context_t ctx)3996 VNOP_MMAP(vnode_t vp, int fflags, vfs_context_t ctx)
3997 {
3998 	int _err;
3999 	struct vnop_mmap_args a;
4000 
4001 	a.a_desc = &vnop_mmap_desc;
4002 	a.a_vp = vp;
4003 	a.a_fflags = fflags;
4004 	a.a_context = ctx;
4005 
4006 	_err = (*vp->v_op[vnop_mmap_desc.vdesc_offset])(&a);
4007 	DTRACE_FSINFO(mmap, vnode_t, vp);
4008 
4009 	return _err;
4010 }
4011 
4012 
4013 #if 0
4014 /*
4015 *#
4016 *# mnomap - vp U U U
4017 *#
4018 */
4019 struct vnop_mnomap_args {
4020 	struct vnodeop_desc *a_desc;
4021 	vnode_t a_vp;
4022 	vfs_context_t a_context;
4023 };
4024 #endif /* 0*/
4025 errno_t
VNOP_MNOMAP(vnode_t vp,vfs_context_t ctx)4026 VNOP_MNOMAP(vnode_t vp, vfs_context_t ctx)
4027 {
4028 	int _err;
4029 	struct vnop_mnomap_args a;
4030 
4031 	a.a_desc = &vnop_mnomap_desc;
4032 	a.a_vp = vp;
4033 	a.a_context = ctx;
4034 
4035 	_err = (*vp->v_op[vnop_mnomap_desc.vdesc_offset])(&a);
4036 	DTRACE_FSINFO(mnomap, vnode_t, vp);
4037 
4038 	return _err;
4039 }
4040 
4041 
4042 #if 0
4043 /*
4044 *#
4045 *#% fsync        vp      L L L
4046 *#
4047 */
4048 struct vnop_fsync_args {
4049 	struct vnodeop_desc *a_desc;
4050 	vnode_t a_vp;
4051 	int a_waitfor;
4052 	vfs_context_t a_context;
4053 };
4054 #endif /* 0*/
4055 errno_t
VNOP_FSYNC(vnode_t vp,int waitfor,vfs_context_t ctx)4056 VNOP_FSYNC(vnode_t vp, int waitfor, vfs_context_t ctx)
4057 {
4058 	struct vnop_fsync_args a;
4059 	int _err;
4060 
4061 	a.a_desc = &vnop_fsync_desc;
4062 	a.a_vp = vp;
4063 	a.a_waitfor = waitfor;
4064 	a.a_context = ctx;
4065 
4066 	_err = (*vp->v_op[vnop_fsync_desc.vdesc_offset])(&a);
4067 	DTRACE_FSINFO(fsync, vnode_t, vp);
4068 
4069 	return _err;
4070 }
4071 
4072 
4073 #if 0
4074 /*
4075 *#
4076 *#% remove       dvp     L U U
4077 *#% remove       vp      L U U
4078 *#
4079 */
4080 struct vnop_remove_args {
4081 	struct vnodeop_desc *a_desc;
4082 	vnode_t a_dvp;
4083 	vnode_t a_vp;
4084 	struct componentname *a_cnp;
4085 	int a_flags;
4086 	vfs_context_t a_context;
4087 };
4088 #endif /* 0*/
4089 errno_t
VNOP_REMOVE(vnode_t dvp,vnode_t vp,struct componentname * cnp,int flags,vfs_context_t ctx)4090 VNOP_REMOVE(vnode_t dvp, vnode_t vp, struct componentname * cnp, int flags, vfs_context_t ctx)
4091 {
4092 	int _err;
4093 	struct vnop_remove_args a;
4094 
4095 	a.a_desc = &vnop_remove_desc;
4096 	a.a_dvp = dvp;
4097 	a.a_vp = vp;
4098 	a.a_cnp = cnp;
4099 	a.a_flags = flags;
4100 	a.a_context = ctx;
4101 
4102 	_err = (*dvp->v_op[vnop_remove_desc.vdesc_offset])(&a);
4103 	DTRACE_FSINFO(remove, vnode_t, vp);
4104 
4105 	if (_err == 0) {
4106 		vnode_setneedinactive(vp);
4107 #if CONFIG_APPLEDOUBLE
4108 		if (!(NATIVE_XATTR(dvp))) {
4109 			/*
4110 			 * Remove any associated extended attribute file (._ AppleDouble file).
4111 			 */
4112 			xattrfile_remove(dvp, cnp->cn_nameptr, ctx, 1);
4113 		}
4114 #endif /* CONFIG_APPLEDOUBLE */
4115 	}
4116 
4117 	post_event_if_success(vp, _err, NOTE_DELETE | NOTE_LINK);
4118 	post_event_if_success(dvp, _err, NOTE_WRITE);
4119 
4120 	return _err;
4121 }
4122 
4123 int
VNOP_COMPOUND_REMOVE(vnode_t dvp,vnode_t * vpp,struct nameidata * ndp,int32_t flags,struct vnode_attr * vap,vfs_context_t ctx)4124 VNOP_COMPOUND_REMOVE(vnode_t dvp, vnode_t *vpp, struct nameidata *ndp, int32_t flags, struct vnode_attr *vap, vfs_context_t ctx)
4125 {
4126 	int _err;
4127 	struct vnop_compound_remove_args a;
4128 	int no_vp = (*vpp == NULLVP);
4129 
4130 	a.a_desc = &vnop_compound_remove_desc;
4131 	a.a_dvp = dvp;
4132 	a.a_vpp = vpp;
4133 	a.a_cnp = &ndp->ni_cnd;
4134 	a.a_flags = flags;
4135 	a.a_vap = vap;
4136 	a.a_context = ctx;
4137 	a.a_remove_authorizer = vn_authorize_unlink;
4138 
4139 	_err = (*dvp->v_op[vnop_compound_remove_desc.vdesc_offset])(&a);
4140 	if (_err == 0 && *vpp) {
4141 		DTRACE_FSINFO(compound_remove, vnode_t, *vpp);
4142 	} else {
4143 		DTRACE_FSINFO(compound_remove, vnode_t, dvp);
4144 	}
4145 	if (_err == 0) {
4146 		vnode_setneedinactive(*vpp);
4147 #if CONFIG_APPLEDOUBLE
4148 		if (!(NATIVE_XATTR(dvp))) {
4149 			/*
4150 			 * Remove any associated extended attribute file (._ AppleDouble file).
4151 			 */
4152 			xattrfile_remove(dvp, ndp->ni_cnd.cn_nameptr, ctx, 1);
4153 		}
4154 #endif /* CONFIG_APPLEDOUBLE */
4155 	}
4156 
4157 	post_event_if_success(*vpp, _err, NOTE_DELETE | NOTE_LINK);
4158 	post_event_if_success(dvp, _err, NOTE_WRITE);
4159 
4160 	if (no_vp) {
4161 		lookup_compound_vnop_post_hook(_err, dvp, *vpp, ndp, 0);
4162 		if (*vpp && _err && _err != EKEEPLOOKING) {
4163 			vnode_put(*vpp);
4164 			*vpp = NULLVP;
4165 		}
4166 	}
4167 
4168 	//printf("VNOP_COMPOUND_REMOVE() returning %d\n", _err);
4169 
4170 	return _err;
4171 }
4172 
4173 #if 0
4174 /*
4175 *#
4176 *#% link         vp      U U U
4177 *#% link         tdvp    L U U
4178 *#
4179 */
4180 struct vnop_link_args {
4181 	struct vnodeop_desc *a_desc;
4182 	vnode_t a_vp;
4183 	vnode_t a_tdvp;
4184 	struct componentname *a_cnp;
4185 	vfs_context_t a_context;
4186 };
4187 #endif /* 0*/
4188 errno_t
VNOP_LINK(vnode_t vp,vnode_t tdvp,struct componentname * cnp,vfs_context_t ctx)4189 VNOP_LINK(vnode_t vp, vnode_t tdvp, struct componentname * cnp, vfs_context_t ctx)
4190 {
4191 	int _err;
4192 	struct vnop_link_args a;
4193 
4194 #if CONFIG_APPLEDOUBLE
4195 	/*
4196 	 * For file systems with non-native extended attributes,
4197 	 * disallow linking to an existing "._" Apple Double file.
4198 	 */
4199 	if (!NATIVE_XATTR(tdvp) && (vp->v_type == VREG)) {
4200 		const char   *vname;
4201 
4202 		vname = vnode_getname(vp);
4203 		if (vname != NULL) {
4204 			_err = 0;
4205 			if (vname[0] == '.' && vname[1] == '_' && vname[2] != '\0') {
4206 				_err = EPERM;
4207 			}
4208 			vnode_putname(vname);
4209 			if (_err) {
4210 				return _err;
4211 			}
4212 		}
4213 	}
4214 #endif /* CONFIG_APPLEDOUBLE */
4215 
4216 	a.a_desc = &vnop_link_desc;
4217 	a.a_vp = vp;
4218 	a.a_tdvp = tdvp;
4219 	a.a_cnp = cnp;
4220 	a.a_context = ctx;
4221 
4222 	_err = (*tdvp->v_op[vnop_link_desc.vdesc_offset])(&a);
4223 	DTRACE_FSINFO(link, vnode_t, vp);
4224 
4225 	post_event_if_success(vp, _err, NOTE_LINK);
4226 	post_event_if_success(tdvp, _err, NOTE_WRITE);
4227 
4228 	return _err;
4229 }
4230 
4231 errno_t
vn_rename(struct vnode * fdvp,struct vnode ** fvpp,struct componentname * fcnp,struct vnode_attr * fvap,struct vnode * tdvp,struct vnode ** tvpp,struct componentname * tcnp,struct vnode_attr * tvap,vfs_rename_flags_t flags,vfs_context_t ctx)4232 vn_rename(struct vnode *fdvp, struct vnode **fvpp, struct componentname *fcnp, struct vnode_attr *fvap,
4233     struct vnode *tdvp, struct vnode **tvpp, struct componentname *tcnp, struct vnode_attr *tvap,
4234     vfs_rename_flags_t flags, vfs_context_t ctx)
4235 {
4236 	int _err;
4237 	struct nameidata *fromnd = NULL;
4238 	struct nameidata *tond = NULL;
4239 #if CONFIG_APPLEDOUBLE
4240 	vnode_t src_attr_vp = NULLVP;
4241 	vnode_t dst_attr_vp = NULLVP;
4242 	char smallname1[48];
4243 	char smallname2[48];
4244 	char *xfromname = NULL;
4245 	char *xtoname = NULL;
4246 #endif /* CONFIG_APPLEDOUBLE */
4247 	int batched;
4248 	uint32_t tdfflags;      // Target directory file flags
4249 
4250 	batched = vnode_compound_rename_available(fdvp);
4251 
4252 	if (!batched) {
4253 		if (*fvpp == NULLVP) {
4254 			panic("Not batched, and no fvp?");
4255 		}
4256 	}
4257 
4258 #if CONFIG_APPLEDOUBLE
4259 	/*
4260 	 * We need to preflight any potential AppleDouble file for the source file
4261 	 * before doing the rename operation, since we could potentially be doing
4262 	 * this operation on a network filesystem, and would end up duplicating
4263 	 * the work.  Also, save the source and destination names.  Skip it if the
4264 	 * source has a "._" prefix.
4265 	 */
4266 
4267 	size_t xfromname_len = 0;
4268 	size_t xtoname_len = 0;
4269 	if (!NATIVE_XATTR(fdvp) &&
4270 	    !(fcnp->cn_nameptr[0] == '.' && fcnp->cn_nameptr[1] == '_')) {
4271 		int error;
4272 
4273 		/* Get source attribute file name. */
4274 		xfromname_len = fcnp->cn_namelen + 3;
4275 		if (xfromname_len > sizeof(smallname1)) {
4276 			xfromname = kalloc_data(xfromname_len, Z_WAITOK);
4277 		} else {
4278 			xfromname = &smallname1[0];
4279 		}
4280 		strlcpy(xfromname, "._", xfromname_len);
4281 		strlcat(xfromname, fcnp->cn_nameptr, xfromname_len);
4282 
4283 		/* Get destination attribute file name. */
4284 		xtoname_len = tcnp->cn_namelen + 3;
4285 		if (xtoname_len > sizeof(smallname2)) {
4286 			xtoname = kalloc_data(xtoname_len, Z_WAITOK);
4287 		} else {
4288 			xtoname = &smallname2[0];
4289 		}
4290 		strlcpy(xtoname, "._", xtoname_len);
4291 		strlcat(xtoname, tcnp->cn_nameptr, xtoname_len);
4292 
4293 		/*
4294 		 * Look up source attribute file, keep reference on it if exists.
4295 		 * Note that we do the namei with the nameiop of RENAME, which is different than
4296 		 * in the rename syscall. It's OK if the source file does not exist, since this
4297 		 * is only for AppleDouble files.
4298 		 */
4299 		fromnd = kalloc_type(struct nameidata, Z_WAITOK);
4300 		NDINIT(fromnd, RENAME, OP_RENAME, NOFOLLOW | USEDVP | CN_NBMOUNTLOOK,
4301 		    UIO_SYSSPACE, CAST_USER_ADDR_T(xfromname), ctx);
4302 		fromnd->ni_dvp = fdvp;
4303 		error = namei(fromnd);
4304 
4305 		/*
4306 		 * If there was an error looking up source attribute file,
4307 		 * we'll behave as if it didn't exist.
4308 		 */
4309 
4310 		if (error == 0) {
4311 			if (fromnd->ni_vp) {
4312 				/* src_attr_vp indicates need to call vnode_put / nameidone later */
4313 				src_attr_vp = fromnd->ni_vp;
4314 
4315 				if (fromnd->ni_vp->v_type != VREG) {
4316 					src_attr_vp = NULLVP;
4317 					vnode_put(fromnd->ni_vp);
4318 				}
4319 			}
4320 			/*
4321 			 * Either we got an invalid vnode type (not a regular file) or the namei lookup
4322 			 * suppressed ENOENT as a valid error since we're renaming. Either way, we don't
4323 			 * have a vnode here, so we drop our namei buffer for the source attribute file
4324 			 */
4325 			if (src_attr_vp == NULLVP) {
4326 				nameidone(fromnd);
4327 			}
4328 		}
4329 	}
4330 #endif /* CONFIG_APPLEDOUBLE */
4331 
4332 	if (batched) {
4333 		_err = VNOP_COMPOUND_RENAME(fdvp, fvpp, fcnp, fvap, tdvp, tvpp, tcnp, tvap, flags, ctx);
4334 		if (_err != 0) {
4335 			printf("VNOP_COMPOUND_RENAME() returned %d\n", _err);
4336 		}
4337 	} else {
4338 		if (flags) {
4339 			_err = VNOP_RENAMEX(fdvp, *fvpp, fcnp, tdvp, *tvpp, tcnp, flags, ctx);
4340 			if (_err == ENOTSUP && flags == VFS_RENAME_SECLUDE) {
4341 				// Legacy...
4342 				if ((*fvpp)->v_mount->mnt_vtable->vfc_vfsflags & VFC_VFSVNOP_SECLUDE_RENAME) {
4343 					fcnp->cn_flags |= CN_SECLUDE_RENAME;
4344 					_err = VNOP_RENAME(fdvp, *fvpp, fcnp, tdvp, *tvpp, tcnp, ctx);
4345 				}
4346 			}
4347 		} else {
4348 			_err = VNOP_RENAME(fdvp, *fvpp, fcnp, tdvp, *tvpp, tcnp, ctx);
4349 		}
4350 	}
4351 
4352 	/*
4353 	 * If moved to a new directory that is restricted,
4354 	 * set the restricted flag on the item moved.
4355 	 */
4356 	if (_err == 0) {
4357 		_err = vnode_flags(tdvp, &tdfflags, ctx);
4358 		if (_err == 0) {
4359 			uint32_t inherit_flags = tdfflags & (UF_DATAVAULT | SF_RESTRICTED);
4360 			if (inherit_flags) {
4361 				uint32_t fflags;
4362 				_err = vnode_flags(*fvpp, &fflags, ctx);
4363 				if (_err == 0 && fflags != (fflags | inherit_flags)) {
4364 					struct vnode_attr va;
4365 					VATTR_INIT(&va);
4366 					VATTR_SET(&va, va_flags, fflags | inherit_flags);
4367 					_err = vnode_setattr(*fvpp, &va, ctx);
4368 				}
4369 			}
4370 		}
4371 	}
4372 
4373 #if CONFIG_MACF
4374 	if (_err == 0) {
4375 		mac_vnode_notify_rename(
4376 			ctx,                        /* ctx */
4377 			*fvpp,                      /* fvp */
4378 			fdvp,                       /* fdvp */
4379 			fcnp,                       /* fcnp */
4380 			*tvpp,                      /* tvp */
4381 			tdvp,                       /* tdvp */
4382 			tcnp,                       /* tcnp */
4383 			(flags & VFS_RENAME_SWAP)   /* swap */
4384 			);
4385 	}
4386 #endif
4387 
4388 #if CONFIG_APPLEDOUBLE
4389 	/*
4390 	 * Rename any associated extended attribute file (._ AppleDouble file).
4391 	 */
4392 	if (_err == 0 && !NATIVE_XATTR(fdvp) && xfromname != NULL) {
4393 		int error = 0;
4394 
4395 		/*
4396 		 * Get destination attribute file vnode.
4397 		 * Note that tdvp already has an iocount reference. Make sure to check that we
4398 		 * get a valid vnode from namei.
4399 		 */
4400 		tond = kalloc_type(struct nameidata, Z_WAITOK);
4401 		NDINIT(tond, RENAME, OP_RENAME,
4402 		    NOCACHE | NOFOLLOW | USEDVP | CN_NBMOUNTLOOK, UIO_SYSSPACE,
4403 		    CAST_USER_ADDR_T(xtoname), ctx);
4404 		tond->ni_dvp = tdvp;
4405 		error = namei(tond);
4406 
4407 		if (error) {
4408 			goto ad_error;
4409 		}
4410 
4411 		if (tond->ni_vp) {
4412 			dst_attr_vp = tond->ni_vp;
4413 		}
4414 
4415 		if (src_attr_vp) {
4416 			const char *old_name = src_attr_vp->v_name;
4417 			vnode_t old_parent = src_attr_vp->v_parent;
4418 
4419 			if (batched) {
4420 				error = VNOP_COMPOUND_RENAME(fdvp, &src_attr_vp, &fromnd->ni_cnd, NULL,
4421 				    tdvp, &dst_attr_vp, &tond->ni_cnd, NULL,
4422 				    0, ctx);
4423 			} else {
4424 				error = VNOP_RENAME(fdvp, src_attr_vp, &fromnd->ni_cnd,
4425 				    tdvp, dst_attr_vp, &tond->ni_cnd, ctx);
4426 			}
4427 
4428 			if (error == 0 && old_name == src_attr_vp->v_name &&
4429 			    old_parent == src_attr_vp->v_parent) {
4430 				int update_flags = VNODE_UPDATE_NAME;
4431 
4432 				if (fdvp != tdvp) {
4433 					update_flags |= VNODE_UPDATE_PARENT;
4434 				}
4435 
4436 				if ((src_attr_vp->v_mount->mnt_vtable->vfc_vfsflags & VFC_VFSVNOP_NOUPDATEID_RENAME) == 0) {
4437 					vnode_update_identity(src_attr_vp, tdvp,
4438 					    tond->ni_cnd.cn_nameptr,
4439 					    tond->ni_cnd.cn_namelen,
4440 					    tond->ni_cnd.cn_hash,
4441 					    update_flags);
4442 				}
4443 			}
4444 
4445 			/* kevent notifications for moving resource files
4446 			 * _err is zero if we're here, so no need to notify directories, code
4447 			 * below will do that.  only need to post the rename on the source and
4448 			 * possibly a delete on the dest
4449 			 */
4450 			post_event_if_success(src_attr_vp, error, NOTE_RENAME);
4451 			if (dst_attr_vp) {
4452 				post_event_if_success(dst_attr_vp, error, NOTE_DELETE);
4453 			}
4454 		} else if (dst_attr_vp) {
4455 			/*
4456 			 * Just delete destination attribute file vnode if it exists, since
4457 			 * we didn't have a source attribute file.
4458 			 * Note that tdvp already has an iocount reference.
4459 			 */
4460 
4461 			struct vnop_remove_args args;
4462 
4463 			args.a_desc    = &vnop_remove_desc;
4464 			args.a_dvp     = tdvp;
4465 			args.a_vp      = dst_attr_vp;
4466 			args.a_cnp     = &tond->ni_cnd;
4467 			args.a_context = ctx;
4468 
4469 			if (error == 0) {
4470 				error = (*tdvp->v_op[vnop_remove_desc.vdesc_offset])(&args);
4471 
4472 				if (error == 0) {
4473 					vnode_setneedinactive(dst_attr_vp);
4474 				}
4475 			}
4476 
4477 			/* kevent notification for deleting the destination's attribute file
4478 			 * if it existed.  Only need to post the delete on the destination, since
4479 			 * the code below will handle the directories.
4480 			 */
4481 			post_event_if_success(dst_attr_vp, error, NOTE_DELETE);
4482 		}
4483 	}
4484 ad_error:
4485 	if (src_attr_vp) {
4486 		vnode_put(src_attr_vp);
4487 		nameidone(fromnd);
4488 	}
4489 	if (dst_attr_vp) {
4490 		vnode_put(dst_attr_vp);
4491 		nameidone(tond);
4492 	}
4493 	if (xfromname && xfromname != &smallname1[0]) {
4494 		kfree_data(xfromname, xfromname_len);
4495 	}
4496 	if (xtoname && xtoname != &smallname2[0]) {
4497 		kfree_data(xtoname, xtoname_len);
4498 	}
4499 #endif /* CONFIG_APPLEDOUBLE */
4500 	kfree_type(struct nameidata, fromnd);
4501 	kfree_type(struct nameidata, tond);
4502 	return _err;
4503 }
4504 
4505 
4506 #if 0
4507 /*
4508 *#
4509 *#% rename       fdvp    U U U
4510 *#% rename       fvp     U U U
4511 *#% rename       tdvp    L U U
4512 *#% rename       tvp     X U U
4513 *#
4514 */
4515 struct vnop_rename_args {
4516 	struct vnodeop_desc *a_desc;
4517 	vnode_t a_fdvp;
4518 	vnode_t a_fvp;
4519 	struct componentname *a_fcnp;
4520 	vnode_t a_tdvp;
4521 	vnode_t a_tvp;
4522 	struct componentname *a_tcnp;
4523 	vfs_context_t a_context;
4524 };
4525 #endif /* 0*/
4526 errno_t
VNOP_RENAME(struct vnode * fdvp,struct vnode * fvp,struct componentname * fcnp,struct vnode * tdvp,struct vnode * tvp,struct componentname * tcnp,vfs_context_t ctx)4527 VNOP_RENAME(struct vnode *fdvp, struct vnode *fvp, struct componentname *fcnp,
4528     struct vnode *tdvp, struct vnode *tvp, struct componentname *tcnp,
4529     vfs_context_t ctx)
4530 {
4531 	int _err = 0;
4532 	struct vnop_rename_args a;
4533 
4534 	a.a_desc = &vnop_rename_desc;
4535 	a.a_fdvp = fdvp;
4536 	a.a_fvp = fvp;
4537 	a.a_fcnp = fcnp;
4538 	a.a_tdvp = tdvp;
4539 	a.a_tvp = tvp;
4540 	a.a_tcnp = tcnp;
4541 	a.a_context = ctx;
4542 
4543 	/* do the rename of the main file. */
4544 	_err = (*fdvp->v_op[vnop_rename_desc.vdesc_offset])(&a);
4545 	DTRACE_FSINFO(rename, vnode_t, fdvp);
4546 
4547 	if (_err) {
4548 		return _err;
4549 	}
4550 
4551 	return post_rename(fdvp, fvp, tdvp, tvp);
4552 }
4553 
4554 static errno_t
post_rename(vnode_t fdvp,vnode_t fvp,vnode_t tdvp,vnode_t tvp)4555 post_rename(vnode_t fdvp, vnode_t fvp, vnode_t tdvp, vnode_t tvp)
4556 {
4557 	if (tvp && tvp != fvp) {
4558 		vnode_setneedinactive(tvp);
4559 	}
4560 
4561 	/* Wrote at least one directory.  If transplanted a dir, also changed link counts */
4562 	int events = NOTE_WRITE;
4563 	if (vnode_isdir(fvp)) {
4564 		/* Link count on dir changed only if we are moving a dir and...
4565 		 *      --Moved to new dir, not overwriting there
4566 		 *      --Kept in same dir and DID overwrite
4567 		 */
4568 		if (((fdvp != tdvp) && (!tvp)) || ((fdvp == tdvp) && (tvp))) {
4569 			events |= NOTE_LINK;
4570 		}
4571 	}
4572 
4573 	lock_vnode_and_post(fdvp, events);
4574 	if (fdvp != tdvp) {
4575 		lock_vnode_and_post(tdvp, events);
4576 	}
4577 
4578 	/* If you're replacing the target, post a deletion for it */
4579 	if (tvp) {
4580 		lock_vnode_and_post(tvp, NOTE_DELETE);
4581 	}
4582 
4583 	lock_vnode_and_post(fvp, NOTE_RENAME);
4584 
4585 	return 0;
4586 }
4587 
4588 #if 0
4589 /*
4590 *#
4591 *#% renamex      fdvp    U U U
4592 *#% renamex      fvp     U U U
4593 *#% renamex      tdvp    L U U
4594 *#% renamex      tvp     X U U
4595 *#
4596 */
4597 struct vnop_renamex_args {
4598 	struct vnodeop_desc *a_desc;
4599 	vnode_t a_fdvp;
4600 	vnode_t a_fvp;
4601 	struct componentname *a_fcnp;
4602 	vnode_t a_tdvp;
4603 	vnode_t a_tvp;
4604 	struct componentname *a_tcnp;
4605 	vfs_rename_flags_t a_flags;
4606 	vfs_context_t a_context;
4607 };
4608 #endif /* 0*/
4609 errno_t
VNOP_RENAMEX(struct vnode * fdvp,struct vnode * fvp,struct componentname * fcnp,struct vnode * tdvp,struct vnode * tvp,struct componentname * tcnp,vfs_rename_flags_t flags,vfs_context_t ctx)4610 VNOP_RENAMEX(struct vnode *fdvp, struct vnode *fvp, struct componentname *fcnp,
4611     struct vnode *tdvp, struct vnode *tvp, struct componentname *tcnp,
4612     vfs_rename_flags_t flags, vfs_context_t ctx)
4613 {
4614 	int _err = 0;
4615 	struct vnop_renamex_args a;
4616 
4617 	a.a_desc = &vnop_renamex_desc;
4618 	a.a_fdvp = fdvp;
4619 	a.a_fvp = fvp;
4620 	a.a_fcnp = fcnp;
4621 	a.a_tdvp = tdvp;
4622 	a.a_tvp = tvp;
4623 	a.a_tcnp = tcnp;
4624 	a.a_flags = flags;
4625 	a.a_context = ctx;
4626 
4627 	/* do the rename of the main file. */
4628 	_err = (*fdvp->v_op[vnop_renamex_desc.vdesc_offset])(&a);
4629 	DTRACE_FSINFO(renamex, vnode_t, fdvp);
4630 
4631 	if (_err) {
4632 		return _err;
4633 	}
4634 
4635 	return post_rename(fdvp, fvp, tdvp, tvp);
4636 }
4637 
4638 
4639 int
VNOP_COMPOUND_RENAME(struct vnode * fdvp,struct vnode ** fvpp,struct componentname * fcnp,struct vnode_attr * fvap,struct vnode * tdvp,struct vnode ** tvpp,struct componentname * tcnp,struct vnode_attr * tvap,uint32_t flags,vfs_context_t ctx)4640 VNOP_COMPOUND_RENAME(
4641 	struct vnode *fdvp, struct vnode **fvpp, struct componentname *fcnp, struct vnode_attr *fvap,
4642 	struct vnode *tdvp, struct vnode **tvpp, struct componentname *tcnp, struct vnode_attr *tvap,
4643 	uint32_t flags, vfs_context_t ctx)
4644 {
4645 	int _err = 0;
4646 	int events;
4647 	struct vnop_compound_rename_args a;
4648 	int no_fvp, no_tvp;
4649 
4650 	no_fvp = (*fvpp) == NULLVP;
4651 	no_tvp = (*tvpp) == NULLVP;
4652 
4653 	a.a_desc = &vnop_compound_rename_desc;
4654 
4655 	a.a_fdvp = fdvp;
4656 	a.a_fvpp = fvpp;
4657 	a.a_fcnp = fcnp;
4658 	a.a_fvap = fvap;
4659 
4660 	a.a_tdvp = tdvp;
4661 	a.a_tvpp = tvpp;
4662 	a.a_tcnp = tcnp;
4663 	a.a_tvap = tvap;
4664 
4665 	a.a_flags = flags;
4666 	a.a_context = ctx;
4667 	a.a_rename_authorizer = vn_authorize_rename;
4668 	a.a_reserved = NULL;
4669 
4670 	/* do the rename of the main file. */
4671 	_err = (*fdvp->v_op[vnop_compound_rename_desc.vdesc_offset])(&a);
4672 	DTRACE_FSINFO(compound_rename, vnode_t, fdvp);
4673 
4674 	if (_err == 0) {
4675 		if (*tvpp && *tvpp != *fvpp) {
4676 			vnode_setneedinactive(*tvpp);
4677 		}
4678 	}
4679 
4680 	/* Wrote at least one directory.  If transplanted a dir, also changed link counts */
4681 	if (_err == 0 && *fvpp != *tvpp) {
4682 		if (!*fvpp) {
4683 			panic("No fvpp after compound rename?");
4684 		}
4685 
4686 		events = NOTE_WRITE;
4687 		if (vnode_isdir(*fvpp)) {
4688 			/* Link count on dir changed only if we are moving a dir and...
4689 			 *      --Moved to new dir, not overwriting there
4690 			 *      --Kept in same dir and DID overwrite
4691 			 */
4692 			if (((fdvp != tdvp) && (!*tvpp)) || ((fdvp == tdvp) && (*tvpp))) {
4693 				events |= NOTE_LINK;
4694 			}
4695 		}
4696 
4697 		lock_vnode_and_post(fdvp, events);
4698 		if (fdvp != tdvp) {
4699 			lock_vnode_and_post(tdvp, events);
4700 		}
4701 
4702 		/* If you're replacing the target, post a deletion for it */
4703 		if (*tvpp) {
4704 			lock_vnode_and_post(*tvpp, NOTE_DELETE);
4705 		}
4706 
4707 		lock_vnode_and_post(*fvpp, NOTE_RENAME);
4708 	}
4709 
4710 	if (no_fvp) {
4711 		lookup_compound_vnop_post_hook(_err, fdvp, *fvpp, fcnp->cn_ndp, 0);
4712 	}
4713 	if (no_tvp && *tvpp != NULLVP) {
4714 		lookup_compound_vnop_post_hook(_err, tdvp, *tvpp, tcnp->cn_ndp, 0);
4715 	}
4716 
4717 	if (_err && _err != EKEEPLOOKING) {
4718 		if (*fvpp) {
4719 			vnode_put(*fvpp);
4720 			*fvpp = NULLVP;
4721 		}
4722 		if (*tvpp) {
4723 			vnode_put(*tvpp);
4724 			*tvpp = NULLVP;
4725 		}
4726 	}
4727 
4728 	return _err;
4729 }
4730 
4731 int
vn_mkdir(struct vnode * dvp,struct vnode ** vpp,struct nameidata * ndp,struct vnode_attr * vap,vfs_context_t ctx)4732 vn_mkdir(struct vnode *dvp, struct vnode **vpp, struct nameidata *ndp,
4733     struct vnode_attr *vap, vfs_context_t ctx)
4734 {
4735 	if (ndp->ni_cnd.cn_nameiop != CREATE) {
4736 		panic("Non-CREATE nameiop in vn_mkdir()?");
4737 	}
4738 
4739 	if (vnode_compound_mkdir_available(dvp)) {
4740 		return VNOP_COMPOUND_MKDIR(dvp, vpp, ndp, vap, ctx);
4741 	} else {
4742 		return VNOP_MKDIR(dvp, vpp, &ndp->ni_cnd, vap, ctx);
4743 	}
4744 }
4745 
4746 #if 0
4747 /*
4748 *#
4749 *#% mkdir        dvp     L U U
4750 *#% mkdir        vpp     - L -
4751 *#
4752 */
4753 struct vnop_mkdir_args {
4754 	struct vnodeop_desc *a_desc;
4755 	vnode_t a_dvp;
4756 	vnode_t *a_vpp;
4757 	struct componentname *a_cnp;
4758 	struct vnode_attr *a_vap;
4759 	vfs_context_t a_context;
4760 };
4761 #endif /* 0*/
4762 errno_t
VNOP_MKDIR(struct vnode * dvp,struct vnode ** vpp,struct componentname * cnp,struct vnode_attr * vap,vfs_context_t ctx)4763 VNOP_MKDIR(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp,
4764     struct vnode_attr *vap, vfs_context_t ctx)
4765 {
4766 	int _err;
4767 	struct vnop_mkdir_args a;
4768 
4769 	a.a_desc = &vnop_mkdir_desc;
4770 	a.a_dvp = dvp;
4771 	a.a_vpp = vpp;
4772 	a.a_cnp = cnp;
4773 	a.a_vap = vap;
4774 	a.a_context = ctx;
4775 
4776 	_err = (*dvp->v_op[vnop_mkdir_desc.vdesc_offset])(&a);
4777 	if (_err == 0 && *vpp) {
4778 		DTRACE_FSINFO(mkdir, vnode_t, *vpp);
4779 	}
4780 #if CONFIG_APPLEDOUBLE
4781 	if (_err == 0 && !NATIVE_XATTR(dvp)) {
4782 		/*
4783 		 * Remove stale Apple Double file (if any).
4784 		 */
4785 		xattrfile_remove(dvp, cnp->cn_nameptr, ctx, 0);
4786 	}
4787 #endif /* CONFIG_APPLEDOUBLE */
4788 
4789 	post_event_if_success(dvp, _err, NOTE_LINK | NOTE_WRITE);
4790 
4791 	return _err;
4792 }
4793 
4794 int
VNOP_COMPOUND_MKDIR(struct vnode * dvp,struct vnode ** vpp,struct nameidata * ndp,struct vnode_attr * vap,vfs_context_t ctx)4795 VNOP_COMPOUND_MKDIR(struct vnode *dvp, struct vnode **vpp, struct nameidata *ndp,
4796     struct vnode_attr *vap, vfs_context_t ctx)
4797 {
4798 	int _err;
4799 	struct vnop_compound_mkdir_args a;
4800 
4801 	a.a_desc = &vnop_compound_mkdir_desc;
4802 	a.a_dvp = dvp;
4803 	a.a_vpp = vpp;
4804 	a.a_cnp = &ndp->ni_cnd;
4805 	a.a_vap = vap;
4806 	a.a_flags = 0;
4807 	a.a_context = ctx;
4808 #if 0
4809 	a.a_mkdir_authorizer = vn_authorize_mkdir;
4810 #endif /* 0 */
4811 	a.a_reserved = NULL;
4812 
4813 	_err = (*dvp->v_op[vnop_compound_mkdir_desc.vdesc_offset])(&a);
4814 	if (_err == 0 && *vpp) {
4815 		DTRACE_FSINFO(compound_mkdir, vnode_t, *vpp);
4816 	}
4817 #if CONFIG_APPLEDOUBLE
4818 	if (_err == 0 && !NATIVE_XATTR(dvp)) {
4819 		/*
4820 		 * Remove stale Apple Double file (if any).
4821 		 */
4822 		xattrfile_remove(dvp, ndp->ni_cnd.cn_nameptr, ctx, 0);
4823 	}
4824 #endif /* CONFIG_APPLEDOUBLE */
4825 
4826 	post_event_if_success(dvp, _err, NOTE_LINK | NOTE_WRITE);
4827 
4828 	lookup_compound_vnop_post_hook(_err, dvp, *vpp, ndp, (_err == 0));
4829 	if (*vpp && _err && _err != EKEEPLOOKING) {
4830 		vnode_put(*vpp);
4831 		*vpp = NULLVP;
4832 	}
4833 
4834 	return _err;
4835 }
4836 
4837 int
vn_rmdir(vnode_t dvp,vnode_t * vpp,struct nameidata * ndp,struct vnode_attr * vap,vfs_context_t ctx)4838 vn_rmdir(vnode_t dvp, vnode_t *vpp, struct nameidata *ndp, struct vnode_attr *vap, vfs_context_t ctx)
4839 {
4840 	if (vnode_compound_rmdir_available(dvp)) {
4841 		return VNOP_COMPOUND_RMDIR(dvp, vpp, ndp, vap, ctx);
4842 	} else {
4843 		if (*vpp == NULLVP) {
4844 			panic("NULL vp, but not a compound VNOP?");
4845 		}
4846 		if (vap != NULL) {
4847 			panic("Non-NULL vap, but not a compound VNOP?");
4848 		}
4849 		return VNOP_RMDIR(dvp, *vpp, &ndp->ni_cnd, ctx);
4850 	}
4851 }
4852 
4853 #if 0
4854 /*
4855 *#
4856 *#% rmdir        dvp     L U U
4857 *#% rmdir        vp      L U U
4858 *#
4859 */
4860 struct vnop_rmdir_args {
4861 	struct vnodeop_desc *a_desc;
4862 	vnode_t a_dvp;
4863 	vnode_t a_vp;
4864 	struct componentname *a_cnp;
4865 	vfs_context_t a_context;
4866 };
4867 
4868 #endif /* 0*/
4869 errno_t
VNOP_RMDIR(struct vnode * dvp,struct vnode * vp,struct componentname * cnp,vfs_context_t ctx)4870 VNOP_RMDIR(struct vnode *dvp, struct vnode *vp, struct componentname *cnp, vfs_context_t ctx)
4871 {
4872 	int _err;
4873 	struct vnop_rmdir_args a;
4874 
4875 	a.a_desc = &vnop_rmdir_desc;
4876 	a.a_dvp = dvp;
4877 	a.a_vp = vp;
4878 	a.a_cnp = cnp;
4879 	a.a_context = ctx;
4880 
4881 	_err = (*vp->v_op[vnop_rmdir_desc.vdesc_offset])(&a);
4882 	DTRACE_FSINFO(rmdir, vnode_t, vp);
4883 
4884 	if (_err == 0) {
4885 		vnode_setneedinactive(vp);
4886 #if CONFIG_APPLEDOUBLE
4887 		if (!(NATIVE_XATTR(dvp))) {
4888 			/*
4889 			 * Remove any associated extended attribute file (._ AppleDouble file).
4890 			 */
4891 			xattrfile_remove(dvp, cnp->cn_nameptr, ctx, 1);
4892 		}
4893 #endif
4894 	}
4895 
4896 	/* If you delete a dir, it loses its "." reference --> NOTE_LINK */
4897 	post_event_if_success(vp, _err, NOTE_DELETE | NOTE_LINK);
4898 	post_event_if_success(dvp, _err, NOTE_LINK | NOTE_WRITE);
4899 
4900 	return _err;
4901 }
4902 
4903 int
VNOP_COMPOUND_RMDIR(struct vnode * dvp,struct vnode ** vpp,struct nameidata * ndp,struct vnode_attr * vap,vfs_context_t ctx)4904 VNOP_COMPOUND_RMDIR(struct vnode *dvp, struct vnode **vpp, struct nameidata *ndp,
4905     struct vnode_attr *vap, vfs_context_t ctx)
4906 {
4907 	int _err;
4908 	struct vnop_compound_rmdir_args a;
4909 	int no_vp;
4910 
4911 	a.a_desc = &vnop_mkdir_desc;
4912 	a.a_dvp = dvp;
4913 	a.a_vpp = vpp;
4914 	a.a_cnp = &ndp->ni_cnd;
4915 	a.a_vap = vap;
4916 	a.a_flags = 0;
4917 	a.a_context = ctx;
4918 	a.a_rmdir_authorizer = vn_authorize_rmdir;
4919 	a.a_reserved = NULL;
4920 
4921 	no_vp = (*vpp == NULLVP);
4922 
4923 	_err = (*dvp->v_op[vnop_compound_rmdir_desc.vdesc_offset])(&a);
4924 	if (_err == 0 && *vpp) {
4925 		DTRACE_FSINFO(compound_rmdir, vnode_t, *vpp);
4926 	}
4927 #if CONFIG_APPLEDOUBLE
4928 	if (_err == 0 && !NATIVE_XATTR(dvp)) {
4929 		/*
4930 		 * Remove stale Apple Double file (if any).
4931 		 */
4932 		xattrfile_remove(dvp, ndp->ni_cnd.cn_nameptr, ctx, 0);
4933 	}
4934 #endif
4935 
4936 	if (*vpp) {
4937 		post_event_if_success(*vpp, _err, NOTE_DELETE | NOTE_LINK);
4938 	}
4939 	post_event_if_success(dvp, _err, NOTE_LINK | NOTE_WRITE);
4940 
4941 	if (no_vp) {
4942 		lookup_compound_vnop_post_hook(_err, dvp, *vpp, ndp, 0);
4943 
4944 #if 0 /* Removing orphaned ._ files requires a vp.... */
4945 		if (*vpp && _err && _err != EKEEPLOOKING) {
4946 			vnode_put(*vpp);
4947 			*vpp = NULLVP;
4948 		}
4949 #endif  /* 0 */
4950 	}
4951 
4952 	return _err;
4953 }
4954 
4955 #if CONFIG_APPLEDOUBLE
4956 /*
4957  * Remove a ._ AppleDouble file
4958  */
4959 #define AD_STALE_SECS  (180)
4960 static void
xattrfile_remove(vnode_t dvp,const char * basename,vfs_context_t ctx,int force)4961 xattrfile_remove(vnode_t dvp, const char * basename, vfs_context_t ctx, int force)
4962 {
4963 	vnode_t xvp;
4964 	struct nameidata nd;
4965 	char smallname[64];
4966 	char *filename = NULL;
4967 	size_t alloc_len;
4968 	size_t copy_len;
4969 
4970 	if ((basename == NULL) || (basename[0] == '\0') ||
4971 	    (basename[0] == '.' && basename[1] == '_')) {
4972 		return;
4973 	}
4974 	filename = &smallname[0];
4975 	alloc_len = snprintf(filename, sizeof(smallname), "._%s", basename);
4976 	if (alloc_len >= sizeof(smallname)) {
4977 		alloc_len++;  /* snprintf result doesn't include '\0' */
4978 		filename = kalloc_data(alloc_len, Z_WAITOK);
4979 		copy_len = snprintf(filename, alloc_len, "._%s", basename);
4980 	}
4981 	NDINIT(&nd, DELETE, OP_UNLINK, WANTPARENT | LOCKLEAF | NOFOLLOW | USEDVP, UIO_SYSSPACE,
4982 	    CAST_USER_ADDR_T(filename), ctx);
4983 	nd.ni_dvp = dvp;
4984 	if (namei(&nd) != 0) {
4985 		goto out2;
4986 	}
4987 
4988 	xvp = nd.ni_vp;
4989 	nameidone(&nd);
4990 	if (xvp->v_type != VREG) {
4991 		goto out1;
4992 	}
4993 
4994 	/*
4995 	 * When creating a new object and a "._" file already
4996 	 * exists, check to see if its a stale "._" file.
4997 	 *
4998 	 */
4999 	if (!force) {
5000 		struct vnode_attr va;
5001 
5002 		VATTR_INIT(&va);
5003 		VATTR_WANTED(&va, va_data_size);
5004 		VATTR_WANTED(&va, va_modify_time);
5005 		if (VNOP_GETATTR(xvp, &va, ctx) == 0 &&
5006 		    VATTR_IS_SUPPORTED(&va, va_data_size) &&
5007 		    VATTR_IS_SUPPORTED(&va, va_modify_time) &&
5008 		    va.va_data_size != 0) {
5009 			struct timeval tv;
5010 
5011 			microtime(&tv);
5012 			if ((tv.tv_sec > va.va_modify_time.tv_sec) &&
5013 			    (tv.tv_sec - va.va_modify_time.tv_sec) > AD_STALE_SECS) {
5014 				force = 1;  /* must be stale */
5015 			}
5016 		}
5017 	}
5018 	if (force) {
5019 		int  error;
5020 
5021 		error = VNOP_REMOVE(dvp, xvp, &nd.ni_cnd, 0, ctx);
5022 		if (error == 0) {
5023 			vnode_setneedinactive(xvp);
5024 		}
5025 
5026 		post_event_if_success(xvp, error, NOTE_DELETE);
5027 		post_event_if_success(dvp, error, NOTE_WRITE);
5028 	}
5029 
5030 out1:
5031 	vnode_put(dvp);
5032 	vnode_put(xvp);
5033 out2:
5034 	if (filename && filename != &smallname[0]) {
5035 		kfree_data(filename, alloc_len);
5036 	}
5037 }
5038 
5039 /*
5040  * Shadow uid/gid/mod to a ._ AppleDouble file
5041  */
5042 static void
xattrfile_setattr(vnode_t dvp,const char * basename,struct vnode_attr * vap,vfs_context_t ctx)5043 xattrfile_setattr(vnode_t dvp, const char * basename, struct vnode_attr * vap,
5044     vfs_context_t ctx)
5045 {
5046 	vnode_t xvp;
5047 	struct nameidata nd;
5048 	char smallname[64];
5049 	char *filename = NULL;
5050 	size_t alloc_len;
5051 	size_t copy_len;
5052 
5053 	if ((dvp == NULLVP) ||
5054 	    (basename == NULL) || (basename[0] == '\0') ||
5055 	    (basename[0] == '.' && basename[1] == '_')) {
5056 		return;
5057 	}
5058 	filename = &smallname[0];
5059 	alloc_len = snprintf(filename, sizeof(smallname), "._%s", basename);
5060 	if (alloc_len >= sizeof(smallname)) {
5061 		alloc_len++;  /* snprintf result doesn't include '\0' */
5062 		filename = kalloc_data(alloc_len, Z_WAITOK);
5063 		copy_len = snprintf(filename, alloc_len, "._%s", basename);
5064 	}
5065 	NDINIT(&nd, LOOKUP, OP_SETATTR, NOFOLLOW | USEDVP, UIO_SYSSPACE,
5066 	    CAST_USER_ADDR_T(filename), ctx);
5067 	nd.ni_dvp = dvp;
5068 	if (namei(&nd) != 0) {
5069 		goto out2;
5070 	}
5071 
5072 	xvp = nd.ni_vp;
5073 	nameidone(&nd);
5074 
5075 	if (xvp->v_type == VREG) {
5076 		struct vnop_setattr_args a;
5077 
5078 		a.a_desc = &vnop_setattr_desc;
5079 		a.a_vp = xvp;
5080 		a.a_vap = vap;
5081 		a.a_context = ctx;
5082 
5083 		(void) (*xvp->v_op[vnop_setattr_desc.vdesc_offset])(&a);
5084 	}
5085 
5086 	vnode_put(xvp);
5087 out2:
5088 	if (filename && filename != &smallname[0]) {
5089 		kfree_data(filename, alloc_len);
5090 	}
5091 }
5092 #endif /* CONFIG_APPLEDOUBLE */
5093 
5094  #if 0
5095 /*
5096 *#
5097 *#% symlink      dvp     L U U
5098 *#% symlink      vpp     - U -
5099 *#
5100 */
5101 struct vnop_symlink_args {
5102 	struct vnodeop_desc *a_desc;
5103 	vnode_t a_dvp;
5104 	vnode_t *a_vpp;
5105 	struct componentname *a_cnp;
5106 	struct vnode_attr *a_vap;
5107 	char *a_target;
5108 	vfs_context_t a_context;
5109 };
5110 
5111 #endif /* 0*/
5112 errno_t
VNOP_SYMLINK(struct vnode * dvp,struct vnode ** vpp,struct componentname * cnp,struct vnode_attr * vap,char * target,vfs_context_t ctx)5113 VNOP_SYMLINK(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp,
5114     struct vnode_attr *vap, char *target, vfs_context_t ctx)
5115 {
5116 	int _err;
5117 	struct vnop_symlink_args a;
5118 
5119 	a.a_desc = &vnop_symlink_desc;
5120 	a.a_dvp = dvp;
5121 	a.a_vpp = vpp;
5122 	a.a_cnp = cnp;
5123 	a.a_vap = vap;
5124 	a.a_target = target;
5125 	a.a_context = ctx;
5126 
5127 	_err = (*dvp->v_op[vnop_symlink_desc.vdesc_offset])(&a);
5128 	DTRACE_FSINFO(symlink, vnode_t, dvp);
5129 #if CONFIG_APPLEDOUBLE
5130 	if (_err == 0 && !NATIVE_XATTR(dvp)) {
5131 		/*
5132 		 * Remove stale Apple Double file (if any).  Posts its own knotes
5133 		 */
5134 		xattrfile_remove(dvp, cnp->cn_nameptr, ctx, 0);
5135 	}
5136 #endif /* CONFIG_APPLEDOUBLE */
5137 
5138 	post_event_if_success(dvp, _err, NOTE_WRITE);
5139 
5140 	return _err;
5141 }
5142 
5143 #if 0
5144 /*
5145 *#
5146 *#% readdir      vp      L L L
5147 *#
5148 */
5149 struct vnop_readdir_args {
5150 	struct vnodeop_desc *a_desc;
5151 	vnode_t a_vp;
5152 	struct uio *a_uio;
5153 	int a_flags;
5154 	int *a_eofflag;
5155 	int *a_numdirent;
5156 	vfs_context_t a_context;
5157 };
5158 
5159 #endif /* 0*/
5160 errno_t
VNOP_READDIR(struct vnode * vp,struct uio * uio,int flags,int * eofflag,int * numdirent,vfs_context_t ctx)5161 VNOP_READDIR(struct vnode *vp, struct uio *uio, int flags, int *eofflag,
5162     int *numdirent, vfs_context_t ctx)
5163 {
5164 	int _err;
5165 	struct vnop_readdir_args a;
5166 #if CONFIG_DTRACE
5167 	user_ssize_t resid = uio_resid(uio);
5168 #endif
5169 
5170 	a.a_desc = &vnop_readdir_desc;
5171 	a.a_vp = vp;
5172 	a.a_uio = uio;
5173 	a.a_flags = flags;
5174 	a.a_eofflag = eofflag;
5175 	a.a_numdirent = numdirent;
5176 	a.a_context = ctx;
5177 
5178 	_err = (*vp->v_op[vnop_readdir_desc.vdesc_offset])(&a);
5179 	DTRACE_FSINFO_IO(readdir,
5180 	    vnode_t, vp, user_ssize_t, (resid - uio_resid(uio)));
5181 
5182 	return _err;
5183 }
5184 
5185 #if 0
5186 /*
5187 *#
5188 *#% readdirattr  vp      L L L
5189 *#
5190 */
5191 struct vnop_readdirattr_args {
5192 	struct vnodeop_desc *a_desc;
5193 	vnode_t a_vp;
5194 	struct attrlist *a_alist;
5195 	struct uio *a_uio;
5196 	uint32_t a_maxcount;
5197 	uint32_t a_options;
5198 	uint32_t *a_newstate;
5199 	int *a_eofflag;
5200 	uint32_t *a_actualcount;
5201 	vfs_context_t a_context;
5202 };
5203 
5204 #endif /* 0*/
5205 errno_t
VNOP_READDIRATTR(struct vnode * vp,struct attrlist * alist,struct uio * uio,uint32_t maxcount,uint32_t options,uint32_t * newstate,int * eofflag,uint32_t * actualcount,vfs_context_t ctx)5206 VNOP_READDIRATTR(struct vnode *vp, struct attrlist *alist, struct uio *uio, uint32_t maxcount,
5207     uint32_t options, uint32_t *newstate, int *eofflag, uint32_t *actualcount, vfs_context_t ctx)
5208 {
5209 	int _err;
5210 	struct vnop_readdirattr_args a;
5211 #if CONFIG_DTRACE
5212 	user_ssize_t resid = uio_resid(uio);
5213 #endif
5214 
5215 	a.a_desc = &vnop_readdirattr_desc;
5216 	a.a_vp = vp;
5217 	a.a_alist = alist;
5218 	a.a_uio = uio;
5219 	a.a_maxcount = maxcount;
5220 	a.a_options = options;
5221 	a.a_newstate = newstate;
5222 	a.a_eofflag = eofflag;
5223 	a.a_actualcount = actualcount;
5224 	a.a_context = ctx;
5225 
5226 	_err = (*vp->v_op[vnop_readdirattr_desc.vdesc_offset])(&a);
5227 	DTRACE_FSINFO_IO(readdirattr,
5228 	    vnode_t, vp, user_ssize_t, (resid - uio_resid(uio)));
5229 
5230 	return _err;
5231 }
5232 
5233 #if 0
5234 struct vnop_getttrlistbulk_args {
5235 	struct vnodeop_desc *a_desc;
5236 	vnode_t a_vp;
5237 	struct attrlist *a_alist;
5238 	struct vnode_attr *a_vap;
5239 	struct uio *a_uio;
5240 	void *a_private
5241 	uint64_t a_options;
5242 	int *a_eofflag;
5243 	uint32_t *a_actualcount;
5244 	vfs_context_t a_context;
5245 };
5246 #endif /* 0*/
5247 errno_t
VNOP_GETATTRLISTBULK(struct vnode * vp,struct attrlist * alist,struct vnode_attr * vap,struct uio * uio,void * private,uint64_t options,int32_t * eofflag,int32_t * actualcount,vfs_context_t ctx)5248 VNOP_GETATTRLISTBULK(struct vnode *vp, struct attrlist *alist,
5249     struct vnode_attr *vap, struct uio *uio, void *private, uint64_t options,
5250     int32_t *eofflag, int32_t *actualcount, vfs_context_t ctx)
5251 {
5252 	int _err;
5253 	struct vnop_getattrlistbulk_args a;
5254 #if CONFIG_DTRACE
5255 	user_ssize_t resid = uio_resid(uio);
5256 #endif
5257 
5258 	a.a_desc = &vnop_getattrlistbulk_desc;
5259 	a.a_vp = vp;
5260 	a.a_alist = alist;
5261 	a.a_vap = vap;
5262 	a.a_uio = uio;
5263 	a.a_private = private;
5264 	a.a_options = options;
5265 	a.a_eofflag = eofflag;
5266 	a.a_actualcount = actualcount;
5267 	a.a_context = ctx;
5268 
5269 	_err = (*vp->v_op[vnop_getattrlistbulk_desc.vdesc_offset])(&a);
5270 	DTRACE_FSINFO_IO(getattrlistbulk,
5271 	    vnode_t, vp, user_ssize_t, (resid - uio_resid(uio)));
5272 
5273 	return _err;
5274 }
5275 
5276 #if 0
5277 /*
5278 *#
5279 *#% readlink     vp      L L L
5280 *#
5281 */
5282 struct vnop_readlink_args {
5283 	struct vnodeop_desc *a_desc;
5284 	vnode_t a_vp;
5285 	struct uio *a_uio;
5286 	vfs_context_t a_context;
5287 };
5288 #endif /* 0 */
5289 
5290 /*
5291  * Returns:	0			Success
5292  *		lock_fsnode:ENOENT	No such file or directory [only for VFS
5293  *					 that is not thread safe & vnode is
5294  *					 currently being/has been terminated]
5295  *		<vfs_readlink>:EINVAL
5296  *		<vfs_readlink>:???
5297  *
5298  * Note:	The return codes from the underlying VFS's readlink routine
5299  *		can't be fully enumerated here, since third party VFS authors
5300  *		may not limit their error returns to the ones documented here,
5301  *		even though this may result in some programs functioning
5302  *		incorrectly.
5303  *
5304  *		The return codes documented above are those which may currently
5305  *		be returned by HFS from hfs_vnop_readlink, not including
5306  *		additional error code which may be propagated from underlying
5307  *		routines.
5308  */
5309 errno_t
VNOP_READLINK(struct vnode * vp,struct uio * uio,vfs_context_t ctx)5310 VNOP_READLINK(struct vnode *vp, struct uio *uio, vfs_context_t ctx)
5311 {
5312 	int _err;
5313 	struct vnop_readlink_args a;
5314 #if CONFIG_DTRACE
5315 	user_ssize_t resid = uio_resid(uio);
5316 #endif
5317 	a.a_desc = &vnop_readlink_desc;
5318 	a.a_vp = vp;
5319 	a.a_uio = uio;
5320 	a.a_context = ctx;
5321 
5322 	_err = (*vp->v_op[vnop_readlink_desc.vdesc_offset])(&a);
5323 	DTRACE_FSINFO_IO(readlink,
5324 	    vnode_t, vp, user_ssize_t, (resid - uio_resid(uio)));
5325 
5326 	return _err;
5327 }
5328 
5329 #if 0
5330 /*
5331 *#
5332 *#% inactive     vp      L U U
5333 *#
5334 */
5335 struct vnop_inactive_args {
5336 	struct vnodeop_desc *a_desc;
5337 	vnode_t a_vp;
5338 	vfs_context_t a_context;
5339 };
5340 #endif /* 0*/
5341 errno_t
VNOP_INACTIVE(struct vnode * vp,vfs_context_t ctx)5342 VNOP_INACTIVE(struct vnode *vp, vfs_context_t ctx)
5343 {
5344 	int _err;
5345 	struct vnop_inactive_args a;
5346 
5347 	a.a_desc = &vnop_inactive_desc;
5348 	a.a_vp = vp;
5349 	a.a_context = ctx;
5350 
5351 	_err = (*vp->v_op[vnop_inactive_desc.vdesc_offset])(&a);
5352 	DTRACE_FSINFO(inactive, vnode_t, vp);
5353 
5354 #if NAMEDSTREAMS
5355 	/* For file systems that do not support namedstream natively, mark
5356 	 * the shadow stream file vnode to be recycled as soon as the last
5357 	 * reference goes away.  To avoid re-entering reclaim code, do not
5358 	 * call recycle on terminating namedstream vnodes.
5359 	 */
5360 	if (vnode_isnamedstream(vp) &&
5361 	    (vp->v_parent != NULLVP) &&
5362 	    vnode_isshadow(vp) &&
5363 	    ((vp->v_lflag & VL_TERMINATE) == 0)) {
5364 		vnode_recycle(vp);
5365 	}
5366 #endif
5367 
5368 	return _err;
5369 }
5370 
5371 
5372 #if 0
5373 /*
5374 *#
5375 *#% reclaim      vp      U U U
5376 *#
5377 */
5378 struct vnop_reclaim_args {
5379 	struct vnodeop_desc *a_desc;
5380 	vnode_t a_vp;
5381 	vfs_context_t a_context;
5382 };
5383 #endif /* 0*/
5384 errno_t
VNOP_RECLAIM(struct vnode * vp,vfs_context_t ctx)5385 VNOP_RECLAIM(struct vnode *vp, vfs_context_t ctx)
5386 {
5387 	int _err;
5388 	struct vnop_reclaim_args a;
5389 
5390 	a.a_desc = &vnop_reclaim_desc;
5391 	a.a_vp = vp;
5392 	a.a_context = ctx;
5393 
5394 	_err = (*vp->v_op[vnop_reclaim_desc.vdesc_offset])(&a);
5395 	DTRACE_FSINFO(reclaim, vnode_t, vp);
5396 
5397 	return _err;
5398 }
5399 
5400 
5401 /*
5402  * Returns:	0			Success
5403  *	lock_fsnode:ENOENT		No such file or directory [only for VFS
5404  *					 that is not thread safe & vnode is
5405  *					 currently being/has been terminated]
5406  *	<vnop_pathconf_desc>:???	[per FS implementation specific]
5407  */
5408 #if 0
5409 /*
5410 *#
5411 *#% pathconf     vp      L L L
5412 *#
5413 */
5414 struct vnop_pathconf_args {
5415 	struct vnodeop_desc *a_desc;
5416 	vnode_t a_vp;
5417 	int a_name;
5418 	int32_t *a_retval;
5419 	vfs_context_t a_context;
5420 };
5421 #endif /* 0*/
5422 errno_t
VNOP_PATHCONF(struct vnode * vp,int name,int32_t * retval,vfs_context_t ctx)5423 VNOP_PATHCONF(struct vnode *vp, int name, int32_t *retval, vfs_context_t ctx)
5424 {
5425 	int _err;
5426 	struct vnop_pathconf_args a;
5427 
5428 	a.a_desc = &vnop_pathconf_desc;
5429 	a.a_vp = vp;
5430 	a.a_name = name;
5431 	a.a_retval = retval;
5432 	a.a_context = ctx;
5433 
5434 	_err = (*vp->v_op[vnop_pathconf_desc.vdesc_offset])(&a);
5435 	DTRACE_FSINFO(pathconf, vnode_t, vp);
5436 
5437 	return _err;
5438 }
5439 
5440 /*
5441  * Returns:	0			Success
5442  *	err_advlock:ENOTSUP
5443  *	lf_advlock:???
5444  *	<vnop_advlock_desc>:???
5445  *
5446  * Notes:	VFS implementations of advisory locking using calls through
5447  *		<vnop_advlock_desc> because lock enforcement does not occur
5448  *		locally should try to limit themselves to the return codes
5449  *		documented above for lf_advlock and err_advlock.
5450  */
5451 #if 0
5452 /*
5453 *#
5454 *#% advlock      vp      U U U
5455 *#
5456 */
5457 struct vnop_advlock_args {
5458 	struct vnodeop_desc *a_desc;
5459 	vnode_t a_vp;
5460 	caddr_t a_id;
5461 	int a_op;
5462 	struct flock *a_fl;
5463 	int a_flags;
5464 	vfs_context_t a_context;
5465 };
5466 #endif /* 0*/
5467 errno_t
VNOP_ADVLOCK(struct vnode * vp,caddr_t id,int op,struct flock * fl,int flags,vfs_context_t ctx,struct timespec * timeout)5468 VNOP_ADVLOCK(struct vnode *vp, caddr_t id, int op, struct flock *fl, int flags, vfs_context_t ctx, struct timespec *timeout)
5469 {
5470 	int _err;
5471 	struct vnop_advlock_args a;
5472 
5473 	a.a_desc = &vnop_advlock_desc;
5474 	a.a_vp = vp;
5475 	a.a_id = id;
5476 	a.a_op = op;
5477 	a.a_fl = fl;
5478 	a.a_flags = flags;
5479 	a.a_context = ctx;
5480 	a.a_timeout = timeout;
5481 
5482 	/* Disallow advisory locking on non-seekable vnodes */
5483 	if (vnode_isfifo(vp)) {
5484 		_err = err_advlock(&a);
5485 	} else {
5486 		if ((vp->v_flag & VLOCKLOCAL)) {
5487 			/* Advisory locking done at this layer */
5488 			_err = lf_advlock(&a);
5489 		} else if (flags & F_OFD_LOCK) {
5490 			/* Non-local locking doesn't work for OFD locks */
5491 			_err = err_advlock(&a);
5492 		} else {
5493 			/* Advisory locking done by underlying filesystem */
5494 			_err = (*vp->v_op[vnop_advlock_desc.vdesc_offset])(&a);
5495 		}
5496 		DTRACE_FSINFO(advlock, vnode_t, vp);
5497 		if (op == F_UNLCK &&
5498 		    (flags & (F_FLOCK | F_OFD_LOCK)) != 0) {
5499 			post_event_if_success(vp, _err, NOTE_FUNLOCK);
5500 		}
5501 	}
5502 
5503 	return _err;
5504 }
5505 
5506 
5507 
5508 #if 0
5509 /*
5510 *#
5511 *#% allocate     vp      L L L
5512 *#
5513 */
5514 struct vnop_allocate_args {
5515 	struct vnodeop_desc *a_desc;
5516 	vnode_t a_vp;
5517 	off_t a_length;
5518 	u_int32_t a_flags;
5519 	off_t *a_bytesallocated;
5520 	off_t a_offset;
5521 	vfs_context_t a_context;
5522 };
5523 
5524 #endif /* 0*/
5525 errno_t
VNOP_ALLOCATE(struct vnode * vp,off_t length,u_int32_t flags,off_t * bytesallocated,off_t offset,vfs_context_t ctx)5526 VNOP_ALLOCATE(struct vnode *vp, off_t length, u_int32_t flags, off_t *bytesallocated, off_t offset, vfs_context_t ctx)
5527 {
5528 	int _err;
5529 	struct vnop_allocate_args a;
5530 
5531 	a.a_desc = &vnop_allocate_desc;
5532 	a.a_vp = vp;
5533 	a.a_length = length;
5534 	a.a_flags = flags;
5535 	a.a_bytesallocated = bytesallocated;
5536 	a.a_offset = offset;
5537 	a.a_context = ctx;
5538 
5539 	_err = (*vp->v_op[vnop_allocate_desc.vdesc_offset])(&a);
5540 	DTRACE_FSINFO(allocate, vnode_t, vp);
5541 #if CONFIG_FSE
5542 	if (_err == 0) {
5543 		add_fsevent(FSE_STAT_CHANGED, ctx, FSE_ARG_VNODE, vp, FSE_ARG_DONE);
5544 	}
5545 #endif
5546 
5547 	return _err;
5548 }
5549 
5550 #if 0
5551 /*
5552 *#
5553 *#% pagein       vp      = = =
5554 *#
5555 */
5556 struct vnop_pagein_args {
5557 	struct vnodeop_desc *a_desc;
5558 	vnode_t a_vp;
5559 	upl_t a_pl;
5560 	upl_offset_t a_pl_offset;
5561 	off_t a_f_offset;
5562 	size_t a_size;
5563 	int a_flags;
5564 	vfs_context_t a_context;
5565 };
5566 #endif /* 0*/
5567 errno_t
VNOP_PAGEIN(struct vnode * vp,upl_t pl,upl_offset_t pl_offset,off_t f_offset,size_t size,int flags,vfs_context_t ctx)5568 VNOP_PAGEIN(struct vnode *vp, upl_t pl, upl_offset_t pl_offset, off_t f_offset, size_t size, int flags, vfs_context_t ctx)
5569 {
5570 	int _err;
5571 	struct vnop_pagein_args a;
5572 
5573 	a.a_desc = &vnop_pagein_desc;
5574 	a.a_vp = vp;
5575 	a.a_pl = pl;
5576 	a.a_pl_offset = pl_offset;
5577 	a.a_f_offset = f_offset;
5578 	a.a_size = size;
5579 	a.a_flags = flags;
5580 	a.a_context = ctx;
5581 
5582 	_err = (*vp->v_op[vnop_pagein_desc.vdesc_offset])(&a);
5583 	DTRACE_FSINFO(pagein, vnode_t, vp);
5584 
5585 	return _err;
5586 }
5587 
5588 #if 0
5589 /*
5590 *#
5591 *#% pageout      vp      = = =
5592 *#
5593 */
5594 struct vnop_pageout_args {
5595 	struct vnodeop_desc *a_desc;
5596 	vnode_t a_vp;
5597 	upl_t a_pl;
5598 	upl_offset_t a_pl_offset;
5599 	off_t a_f_offset;
5600 	size_t a_size;
5601 	int a_flags;
5602 	vfs_context_t a_context;
5603 };
5604 
5605 #endif /* 0*/
5606 errno_t
VNOP_PAGEOUT(struct vnode * vp,upl_t pl,upl_offset_t pl_offset,off_t f_offset,size_t size,int flags,vfs_context_t ctx)5607 VNOP_PAGEOUT(struct vnode *vp, upl_t pl, upl_offset_t pl_offset, off_t f_offset, size_t size, int flags, vfs_context_t ctx)
5608 {
5609 	int _err;
5610 	struct vnop_pageout_args a;
5611 
5612 	a.a_desc = &vnop_pageout_desc;
5613 	a.a_vp = vp;
5614 	a.a_pl = pl;
5615 	a.a_pl_offset = pl_offset;
5616 	a.a_f_offset = f_offset;
5617 	a.a_size = size;
5618 	a.a_flags = flags;
5619 	a.a_context = ctx;
5620 
5621 	_err = (*vp->v_op[vnop_pageout_desc.vdesc_offset])(&a);
5622 	DTRACE_FSINFO(pageout, vnode_t, vp);
5623 
5624 	post_event_if_success(vp, _err, NOTE_WRITE);
5625 
5626 	return _err;
5627 }
5628 
5629 int
vn_remove(vnode_t dvp,vnode_t * vpp,struct nameidata * ndp,int32_t flags,struct vnode_attr * vap,vfs_context_t ctx)5630 vn_remove(vnode_t dvp, vnode_t *vpp, struct nameidata *ndp, int32_t flags, struct vnode_attr *vap, vfs_context_t ctx)
5631 {
5632 	if (vnode_compound_remove_available(dvp)) {
5633 		return VNOP_COMPOUND_REMOVE(dvp, vpp, ndp, flags, vap, ctx);
5634 	} else {
5635 		return VNOP_REMOVE(dvp, *vpp, &ndp->ni_cnd, flags, ctx);
5636 	}
5637 }
5638 
5639 #if CONFIG_SEARCHFS
5640 
5641 #if 0
5642 /*
5643 *#
5644 *#% searchfs     vp      L L L
5645 *#
5646 */
5647 struct vnop_searchfs_args {
5648 	struct vnodeop_desc *a_desc;
5649 	vnode_t a_vp;
5650 	void *a_searchparams1;
5651 	void *a_searchparams2;
5652 	struct attrlist *a_searchattrs;
5653 	uint32_t a_maxmatches;
5654 	struct timeval *a_timelimit;
5655 	struct attrlist *a_returnattrs;
5656 	uint32_t *a_nummatches;
5657 	uint32_t a_scriptcode;
5658 	uint32_t a_options;
5659 	struct uio *a_uio;
5660 	struct searchstate *a_searchstate;
5661 	vfs_context_t a_context;
5662 };
5663 
5664 #endif /* 0*/
5665 errno_t
VNOP_SEARCHFS(struct vnode * vp,void * searchparams1,void * searchparams2,struct attrlist * searchattrs,uint32_t maxmatches,struct timeval * timelimit,struct attrlist * returnattrs,uint32_t * nummatches,uint32_t scriptcode,uint32_t options,struct uio * uio,struct searchstate * searchstate,vfs_context_t ctx)5666 VNOP_SEARCHFS(struct vnode *vp, void *searchparams1, void *searchparams2, struct attrlist *searchattrs, uint32_t maxmatches, struct timeval *timelimit, struct attrlist *returnattrs, uint32_t *nummatches, uint32_t scriptcode, uint32_t options, struct uio *uio, struct searchstate *searchstate, vfs_context_t ctx)
5667 {
5668 	int _err;
5669 	struct vnop_searchfs_args a;
5670 
5671 	a.a_desc = &vnop_searchfs_desc;
5672 	a.a_vp = vp;
5673 	a.a_searchparams1 = searchparams1;
5674 	a.a_searchparams2 = searchparams2;
5675 	a.a_searchattrs = searchattrs;
5676 	a.a_maxmatches = maxmatches;
5677 	a.a_timelimit = timelimit;
5678 	a.a_returnattrs = returnattrs;
5679 	a.a_nummatches = nummatches;
5680 	a.a_scriptcode = scriptcode;
5681 	a.a_options = options;
5682 	a.a_uio = uio;
5683 	a.a_searchstate = searchstate;
5684 	a.a_context = ctx;
5685 
5686 	_err = (*vp->v_op[vnop_searchfs_desc.vdesc_offset])(&a);
5687 	DTRACE_FSINFO(searchfs, vnode_t, vp);
5688 
5689 	return _err;
5690 }
5691 #endif /* CONFIG_SEARCHFS */
5692 
5693 #if 0
5694 /*
5695 *#
5696 *#% copyfile fvp U U U
5697 *#% copyfile tdvp L U U
5698 *#% copyfile tvp X U U
5699 *#
5700 */
5701 struct vnop_copyfile_args {
5702 	struct vnodeop_desc *a_desc;
5703 	vnode_t a_fvp;
5704 	vnode_t a_tdvp;
5705 	vnode_t a_tvp;
5706 	struct componentname *a_tcnp;
5707 	int a_mode;
5708 	int a_flags;
5709 	vfs_context_t a_context;
5710 };
5711 #endif /* 0*/
5712 errno_t
VNOP_COPYFILE(struct vnode * fvp,struct vnode * tdvp,struct vnode * tvp,struct componentname * tcnp,int mode,int flags,vfs_context_t ctx)5713 VNOP_COPYFILE(struct vnode *fvp, struct vnode *tdvp, struct vnode *tvp, struct componentname *tcnp,
5714     int mode, int flags, vfs_context_t ctx)
5715 {
5716 	int _err;
5717 	struct vnop_copyfile_args a;
5718 	a.a_desc = &vnop_copyfile_desc;
5719 	a.a_fvp = fvp;
5720 	a.a_tdvp = tdvp;
5721 	a.a_tvp = tvp;
5722 	a.a_tcnp = tcnp;
5723 	a.a_mode = mode;
5724 	a.a_flags = flags;
5725 	a.a_context = ctx;
5726 	_err = (*fvp->v_op[vnop_copyfile_desc.vdesc_offset])(&a);
5727 	DTRACE_FSINFO(copyfile, vnode_t, fvp);
5728 	return _err;
5729 }
5730 
5731 #if 0
5732 struct vnop_clonefile_args {
5733 	struct vnodeop_desc *a_desc;
5734 	vnode_t a_fvp;
5735 	vnode_t a_dvp;
5736 	vnode_t *a_vpp;
5737 	struct componentname *a_cnp;
5738 	struct vnode_attr *a_vap;
5739 	uint32_t a_flags;
5740 	vfs_context_t a_context;
5741 	int (*a_dir_clone_authorizer)(  /* Authorization callback */
5742 		struct vnode_attr *vap,         /* attribute to be authorized */
5743 		kauth_action_t action,         /* action for which attribute is to be authorized */
5744 		struct vnode_attr *dvap,         /* target directory attributes */
5745 		vnode_t sdvp,         /* source directory vnode pointer (optional) */
5746 		mount_t mp,         /* mount point of filesystem */
5747 		dir_clone_authorizer_op_t vattr_op,         /* specific operation requested : setup, authorization or cleanup  */
5748 		uint32_t flags;         /* value passed in a_flags to the VNOP */
5749 		vfs_context_t ctx,                      /* As passed to VNOP */
5750 		void *reserved);                        /* Always NULL */
5751 	void *a_reserved;               /* Currently unused */
5752 };
5753 #endif /* 0 */
5754 
5755 errno_t
VNOP_CLONEFILE(vnode_t fvp,vnode_t dvp,vnode_t * vpp,struct componentname * cnp,struct vnode_attr * vap,uint32_t flags,vfs_context_t ctx)5756 VNOP_CLONEFILE(vnode_t fvp, vnode_t dvp, vnode_t *vpp,
5757     struct componentname *cnp, struct vnode_attr *vap, uint32_t flags,
5758     vfs_context_t ctx)
5759 {
5760 	int _err;
5761 	struct vnop_clonefile_args a;
5762 	a.a_desc = &vnop_clonefile_desc;
5763 	a.a_fvp = fvp;
5764 	a.a_dvp = dvp;
5765 	a.a_vpp = vpp;
5766 	a.a_cnp = cnp;
5767 	a.a_vap = vap;
5768 	a.a_flags = flags;
5769 	a.a_context = ctx;
5770 
5771 	if (vnode_vtype(fvp) == VDIR) {
5772 		a.a_dir_clone_authorizer = vnode_attr_authorize_dir_clone;
5773 	} else {
5774 		a.a_dir_clone_authorizer = NULL;
5775 	}
5776 
5777 	_err = (*dvp->v_op[vnop_clonefile_desc.vdesc_offset])(&a);
5778 
5779 	if (_err == 0 && *vpp) {
5780 		DTRACE_FSINFO(clonefile, vnode_t, *vpp);
5781 		if (kdebug_enable) {
5782 			kdebug_lookup(*vpp, cnp);
5783 		}
5784 	}
5785 
5786 	post_event_if_success(dvp, _err, NOTE_WRITE);
5787 
5788 	return _err;
5789 }
5790 
5791 errno_t
VNOP_GETXATTR(vnode_t vp,const char * name,uio_t uio,size_t * size,int options,vfs_context_t ctx)5792 VNOP_GETXATTR(vnode_t vp, const char *name, uio_t uio, size_t *size, int options, vfs_context_t ctx)
5793 {
5794 	struct vnop_getxattr_args a;
5795 	int error;
5796 
5797 	a.a_desc = &vnop_getxattr_desc;
5798 	a.a_vp = vp;
5799 	a.a_name = name;
5800 	a.a_uio = uio;
5801 	a.a_size = size;
5802 	a.a_options = options;
5803 	a.a_context = ctx;
5804 
5805 	error = (*vp->v_op[vnop_getxattr_desc.vdesc_offset])(&a);
5806 	DTRACE_FSINFO(getxattr, vnode_t, vp);
5807 
5808 	return error;
5809 }
5810 
5811 errno_t
VNOP_SETXATTR(vnode_t vp,const char * name,uio_t uio,int options,vfs_context_t ctx)5812 VNOP_SETXATTR(vnode_t vp, const char *name, uio_t uio, int options, vfs_context_t ctx)
5813 {
5814 	struct vnop_setxattr_args a;
5815 	int error;
5816 
5817 	a.a_desc = &vnop_setxattr_desc;
5818 	a.a_vp = vp;
5819 	a.a_name = name;
5820 	a.a_uio = uio;
5821 	a.a_options = options;
5822 	a.a_context = ctx;
5823 
5824 	error = (*vp->v_op[vnop_setxattr_desc.vdesc_offset])(&a);
5825 	DTRACE_FSINFO(setxattr, vnode_t, vp);
5826 
5827 	if (error == 0) {
5828 		vnode_uncache_authorized_action(vp, KAUTH_INVALIDATE_CACHED_RIGHTS);
5829 	}
5830 
5831 	post_event_if_success(vp, error, NOTE_ATTRIB);
5832 
5833 	return error;
5834 }
5835 
5836 errno_t
VNOP_REMOVEXATTR(vnode_t vp,const char * name,int options,vfs_context_t ctx)5837 VNOP_REMOVEXATTR(vnode_t vp, const char *name, int options, vfs_context_t ctx)
5838 {
5839 	struct vnop_removexattr_args a;
5840 	int error;
5841 
5842 	a.a_desc = &vnop_removexattr_desc;
5843 	a.a_vp = vp;
5844 	a.a_name = name;
5845 	a.a_options = options;
5846 	a.a_context = ctx;
5847 
5848 	error = (*vp->v_op[vnop_removexattr_desc.vdesc_offset])(&a);
5849 	DTRACE_FSINFO(removexattr, vnode_t, vp);
5850 
5851 	post_event_if_success(vp, error, NOTE_ATTRIB);
5852 
5853 	return error;
5854 }
5855 
5856 errno_t
VNOP_LISTXATTR(vnode_t vp,uio_t uio,size_t * size,int options,vfs_context_t ctx)5857 VNOP_LISTXATTR(vnode_t vp, uio_t uio, size_t *size, int options, vfs_context_t ctx)
5858 {
5859 	struct vnop_listxattr_args a;
5860 	int error;
5861 
5862 	a.a_desc = &vnop_listxattr_desc;
5863 	a.a_vp = vp;
5864 	a.a_uio = uio;
5865 	a.a_size = size;
5866 	a.a_options = options;
5867 	a.a_context = ctx;
5868 
5869 	error = (*vp->v_op[vnop_listxattr_desc.vdesc_offset])(&a);
5870 	DTRACE_FSINFO(listxattr, vnode_t, vp);
5871 
5872 	return error;
5873 }
5874 
5875 
5876 #if 0
5877 /*
5878 *#
5879 *#% blktooff vp = = =
5880 *#
5881 */
5882 struct vnop_blktooff_args {
5883 	struct vnodeop_desc *a_desc;
5884 	vnode_t a_vp;
5885 	daddr64_t a_lblkno;
5886 	off_t *a_offset;
5887 };
5888 #endif /* 0*/
5889 errno_t
VNOP_BLKTOOFF(struct vnode * vp,daddr64_t lblkno,off_t * offset)5890 VNOP_BLKTOOFF(struct vnode *vp, daddr64_t lblkno, off_t *offset)
5891 {
5892 	int _err;
5893 	struct vnop_blktooff_args a;
5894 
5895 	a.a_desc = &vnop_blktooff_desc;
5896 	a.a_vp = vp;
5897 	a.a_lblkno = lblkno;
5898 	a.a_offset = offset;
5899 
5900 	_err = (*vp->v_op[vnop_blktooff_desc.vdesc_offset])(&a);
5901 	DTRACE_FSINFO(blktooff, vnode_t, vp);
5902 
5903 	return _err;
5904 }
5905 
5906 #if 0
5907 /*
5908 *#
5909 *#% offtoblk vp = = =
5910 *#
5911 */
5912 struct vnop_offtoblk_args {
5913 	struct vnodeop_desc *a_desc;
5914 	vnode_t a_vp;
5915 	off_t a_offset;
5916 	daddr64_t *a_lblkno;
5917 };
5918 #endif /* 0*/
5919 errno_t
VNOP_OFFTOBLK(struct vnode * vp,off_t offset,daddr64_t * lblkno)5920 VNOP_OFFTOBLK(struct vnode *vp, off_t offset, daddr64_t *lblkno)
5921 {
5922 	int _err;
5923 	struct vnop_offtoblk_args a;
5924 
5925 	a.a_desc = &vnop_offtoblk_desc;
5926 	a.a_vp = vp;
5927 	a.a_offset = offset;
5928 	a.a_lblkno = lblkno;
5929 
5930 	_err = (*vp->v_op[vnop_offtoblk_desc.vdesc_offset])(&a);
5931 	DTRACE_FSINFO(offtoblk, vnode_t, vp);
5932 
5933 	return _err;
5934 }
5935 
5936 #if 0
5937 /*
5938 *#
5939 *#% ap vp L L L
5940 *#
5941 */
5942 struct vnop_verify_args {
5943 	struct vnodeop_desc *a_desc;
5944 	vnode_t a_vp;
5945 	off_t a_foffset;
5946 	char *a_buf;
5947 	size_t a_bufsize;
5948 	size_t *a_verifyblksize;
5949 	void **a_verify_ctxp;
5950 	int a_flags;
5951 	vfs_context_t a_context;
5952 };
5953 #endif
5954 
5955 errno_t
VNOP_VERIFY(struct vnode * vp,off_t foffset,uint8_t * buf,size_t bufsize,size_t * verify_block_size,void ** verify_ctxp,vnode_verify_flags_t flags,vfs_context_t ctx)5956 VNOP_VERIFY(struct vnode *vp, off_t foffset, uint8_t *buf, size_t bufsize,
5957     size_t *verify_block_size, void **verify_ctxp, vnode_verify_flags_t flags,
5958     vfs_context_t ctx)
5959 {
5960 	int _err;
5961 	struct vnop_verify_args a;
5962 
5963 	if (ctx == NULL) {
5964 		ctx = vfs_context_kernel();
5965 	}
5966 	a.a_desc = &vnop_verify_desc;
5967 	a.a_vp = vp;
5968 	a.a_foffset = foffset;
5969 	a.a_buf = buf;
5970 	a.a_bufsize = bufsize;
5971 	a.a_verifyblksize = verify_block_size;
5972 	a.a_flags = flags;
5973 	a.a_verify_ctxp = verify_ctxp;
5974 	a.a_context = ctx;
5975 
5976 	_err = (*vp->v_op[vnop_verify_desc.vdesc_offset])(&a);
5977 	DTRACE_FSINFO(verify, vnode_t, vp);
5978 
5979 	/* It is not an error for a filesystem to not support this VNOP */
5980 	if (_err == ENOTSUP) {
5981 		if (!buf && verify_block_size) {
5982 			*verify_block_size = 0;
5983 		}
5984 
5985 		_err = 0;
5986 	}
5987 
5988 	return _err;
5989 }
5990 
5991 #if 0
5992 /*
5993 *#
5994 *#% blockmap vp L L L
5995 *#
5996 */
5997 struct vnop_blockmap_args {
5998 	struct vnodeop_desc *a_desc;
5999 	vnode_t a_vp;
6000 	off_t a_foffset;
6001 	size_t a_size;
6002 	daddr64_t *a_bpn;
6003 	size_t *a_run;
6004 	void *a_poff;
6005 	int a_flags;
6006 	vfs_context_t a_context;
6007 };
6008 #endif /* 0*/
6009 errno_t
VNOP_BLOCKMAP(struct vnode * vp,off_t foffset,size_t size,daddr64_t * bpn,size_t * run,void * poff,int flags,vfs_context_t ctx)6010 VNOP_BLOCKMAP(struct vnode *vp, off_t foffset, size_t size, daddr64_t *bpn, size_t *run, void *poff, int flags, vfs_context_t ctx)
6011 {
6012 	int _err;
6013 	struct vnop_blockmap_args a;
6014 	size_t localrun = 0;
6015 
6016 	if (ctx == NULL) {
6017 		ctx = vfs_context_current();
6018 	}
6019 	a.a_desc = &vnop_blockmap_desc;
6020 	a.a_vp = vp;
6021 	a.a_foffset = foffset;
6022 	a.a_size = size;
6023 	a.a_bpn = bpn;
6024 	a.a_run = &localrun;
6025 	a.a_poff = poff;
6026 	a.a_flags = flags;
6027 	a.a_context = ctx;
6028 
6029 	_err = (*vp->v_op[vnop_blockmap_desc.vdesc_offset])(&a);
6030 	DTRACE_FSINFO(blockmap, vnode_t, vp);
6031 
6032 	/*
6033 	 * We used a local variable to request information from the underlying
6034 	 * filesystem about the length of the I/O run in question.  If
6035 	 * we get malformed output from the filesystem, we cap it to the length
6036 	 * requested, at most.  Update 'run' on the way out.
6037 	 */
6038 	if (_err == 0) {
6039 		if (localrun > size) {
6040 			localrun = size;
6041 		}
6042 
6043 		if (run) {
6044 			*run = localrun;
6045 		}
6046 	}
6047 
6048 	return _err;
6049 }
6050 
6051 #if 0
6052 struct vnop_strategy_args {
6053 	struct vnodeop_desc *a_desc;
6054 	struct buf *a_bp;
6055 };
6056 
6057 #endif /* 0*/
6058 errno_t
VNOP_STRATEGY(struct buf * bp)6059 VNOP_STRATEGY(struct buf *bp)
6060 {
6061 	int _err;
6062 	struct vnop_strategy_args a;
6063 	vnode_t vp = buf_vnode(bp);
6064 	a.a_desc = &vnop_strategy_desc;
6065 	a.a_bp = bp;
6066 	_err = (*vp->v_op[vnop_strategy_desc.vdesc_offset])(&a);
6067 	DTRACE_FSINFO(strategy, vnode_t, vp);
6068 	return _err;
6069 }
6070 
6071 #if 0
6072 struct vnop_bwrite_args {
6073 	struct vnodeop_desc *a_desc;
6074 	buf_t a_bp;
6075 };
6076 #endif /* 0*/
6077 errno_t
VNOP_BWRITE(struct buf * bp)6078 VNOP_BWRITE(struct buf *bp)
6079 {
6080 	int _err;
6081 	struct vnop_bwrite_args a;
6082 	vnode_t vp = buf_vnode(bp);
6083 	a.a_desc = &vnop_bwrite_desc;
6084 	a.a_bp = bp;
6085 	_err = (*vp->v_op[vnop_bwrite_desc.vdesc_offset])(&a);
6086 	DTRACE_FSINFO(bwrite, vnode_t, vp);
6087 	return _err;
6088 }
6089 
6090 #if 0
6091 struct vnop_kqfilt_add_args {
6092 	struct vnodeop_desc *a_desc;
6093 	struct vnode *a_vp;
6094 	struct knote *a_kn;
6095 	vfs_context_t a_context;
6096 };
6097 #endif
6098 errno_t
VNOP_KQFILT_ADD(struct vnode * vp,struct knote * kn,vfs_context_t ctx)6099 VNOP_KQFILT_ADD(struct vnode *vp, struct knote *kn, vfs_context_t ctx)
6100 {
6101 	int _err;
6102 	struct vnop_kqfilt_add_args a;
6103 
6104 	a.a_desc = VDESC(vnop_kqfilt_add);
6105 	a.a_vp = vp;
6106 	a.a_kn = kn;
6107 	a.a_context = ctx;
6108 
6109 	_err = (*vp->v_op[vnop_kqfilt_add_desc.vdesc_offset])(&a);
6110 	DTRACE_FSINFO(kqfilt_add, vnode_t, vp);
6111 
6112 	return _err;
6113 }
6114 
6115 #if 0
6116 struct vnop_kqfilt_remove_args {
6117 	struct vnodeop_desc *a_desc;
6118 	struct vnode *a_vp;
6119 	uintptr_t a_ident;
6120 	vfs_context_t a_context;
6121 };
6122 #endif
6123 errno_t
VNOP_KQFILT_REMOVE(struct vnode * vp,uintptr_t ident,vfs_context_t ctx)6124 VNOP_KQFILT_REMOVE(struct vnode *vp, uintptr_t ident, vfs_context_t ctx)
6125 {
6126 	int _err;
6127 	struct vnop_kqfilt_remove_args a;
6128 
6129 	a.a_desc = VDESC(vnop_kqfilt_remove);
6130 	a.a_vp = vp;
6131 	a.a_ident = ident;
6132 	a.a_context = ctx;
6133 
6134 	_err = (*vp->v_op[vnop_kqfilt_remove_desc.vdesc_offset])(&a);
6135 	DTRACE_FSINFO(kqfilt_remove, vnode_t, vp);
6136 
6137 	return _err;
6138 }
6139 
6140 errno_t
VNOP_MONITOR(vnode_t vp,uint32_t events,uint32_t flags,void * handle,vfs_context_t ctx)6141 VNOP_MONITOR(vnode_t vp, uint32_t events, uint32_t flags, void *handle, vfs_context_t ctx)
6142 {
6143 	int _err;
6144 	struct vnop_monitor_args a;
6145 
6146 	a.a_desc = VDESC(vnop_monitor);
6147 	a.a_vp = vp;
6148 	a.a_events = events;
6149 	a.a_flags = flags;
6150 	a.a_handle = handle;
6151 	a.a_context = ctx;
6152 
6153 	_err = (*vp->v_op[vnop_monitor_desc.vdesc_offset])(&a);
6154 	DTRACE_FSINFO(monitor, vnode_t, vp);
6155 
6156 	return _err;
6157 }
6158 
6159 #if 0
6160 struct vnop_setlabel_args {
6161 	struct vnodeop_desc *a_desc;
6162 	struct vnode *a_vp;
6163 	struct label *a_vl;
6164 	vfs_context_t a_context;
6165 };
6166 #endif
6167 errno_t
VNOP_SETLABEL(struct vnode * vp,struct label * label,vfs_context_t ctx)6168 VNOP_SETLABEL(struct vnode *vp, struct label *label, vfs_context_t ctx)
6169 {
6170 	int _err;
6171 	struct vnop_setlabel_args a;
6172 
6173 	a.a_desc = VDESC(vnop_setlabel);
6174 	a.a_vp = vp;
6175 	a.a_vl = label;
6176 	a.a_context = ctx;
6177 
6178 	_err = (*vp->v_op[vnop_setlabel_desc.vdesc_offset])(&a);
6179 	DTRACE_FSINFO(setlabel, vnode_t, vp);
6180 
6181 	return _err;
6182 }
6183 
6184 
6185 #if NAMEDSTREAMS
6186 /*
6187  * Get a named streamed
6188  */
6189 errno_t
VNOP_GETNAMEDSTREAM(vnode_t vp,vnode_t * svpp,const char * name,enum nsoperation operation,int flags,vfs_context_t ctx)6190 VNOP_GETNAMEDSTREAM(vnode_t vp, vnode_t *svpp, const char *name, enum nsoperation operation, int flags, vfs_context_t ctx)
6191 {
6192 	int _err;
6193 	struct vnop_getnamedstream_args a;
6194 
6195 	a.a_desc = &vnop_getnamedstream_desc;
6196 	a.a_vp = vp;
6197 	a.a_svpp = svpp;
6198 	a.a_name = name;
6199 	a.a_operation = operation;
6200 	a.a_flags = flags;
6201 	a.a_context = ctx;
6202 
6203 	_err = (*vp->v_op[vnop_getnamedstream_desc.vdesc_offset])(&a);
6204 	DTRACE_FSINFO(getnamedstream, vnode_t, vp);
6205 	return _err;
6206 }
6207 
6208 /*
6209  * Create a named streamed
6210  */
6211 errno_t
VNOP_MAKENAMEDSTREAM(vnode_t vp,vnode_t * svpp,const char * name,int flags,vfs_context_t ctx)6212 VNOP_MAKENAMEDSTREAM(vnode_t vp, vnode_t *svpp, const char *name, int flags, vfs_context_t ctx)
6213 {
6214 	int _err;
6215 	struct vnop_makenamedstream_args a;
6216 
6217 	a.a_desc = &vnop_makenamedstream_desc;
6218 	a.a_vp = vp;
6219 	a.a_svpp = svpp;
6220 	a.a_name = name;
6221 	a.a_flags = flags;
6222 	a.a_context = ctx;
6223 
6224 	_err = (*vp->v_op[vnop_makenamedstream_desc.vdesc_offset])(&a);
6225 	DTRACE_FSINFO(makenamedstream, vnode_t, vp);
6226 	return _err;
6227 }
6228 
6229 
6230 /*
6231  * Remove a named streamed
6232  */
6233 errno_t
VNOP_REMOVENAMEDSTREAM(vnode_t vp,vnode_t svp,const char * name,int flags,vfs_context_t ctx)6234 VNOP_REMOVENAMEDSTREAM(vnode_t vp, vnode_t svp, const char *name, int flags, vfs_context_t ctx)
6235 {
6236 	int _err;
6237 	struct vnop_removenamedstream_args a;
6238 
6239 	a.a_desc = &vnop_removenamedstream_desc;
6240 	a.a_vp = vp;
6241 	a.a_svp = svp;
6242 	a.a_name = name;
6243 	a.a_flags = flags;
6244 	a.a_context = ctx;
6245 
6246 	_err = (*vp->v_op[vnop_removenamedstream_desc.vdesc_offset])(&a);
6247 	DTRACE_FSINFO(removenamedstream, vnode_t, vp);
6248 	return _err;
6249 }
6250 #endif
6251