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