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